1c4568449SPavel Kumbrasev /*
2c4568449SPavel Kumbrasev Copyright (c) 2022-2023 Intel Corporation
3c4568449SPavel Kumbrasev
4c4568449SPavel Kumbrasev Licensed under the Apache License, Version 2.0 (the "License");
5c4568449SPavel Kumbrasev you may not use this file except in compliance with the License.
6c4568449SPavel Kumbrasev You may obtain a copy of the License at
7c4568449SPavel Kumbrasev
8c4568449SPavel Kumbrasev http://www.apache.org/licenses/LICENSE-2.0
9c4568449SPavel Kumbrasev
10c4568449SPavel Kumbrasev Unless required by applicable law or agreed to in writing, software
11c4568449SPavel Kumbrasev distributed under the License is distributed on an "AS IS" BASIS,
12c4568449SPavel Kumbrasev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c4568449SPavel Kumbrasev See the License for the specific language governing permissions and
14c4568449SPavel Kumbrasev limitations under the License.
15c4568449SPavel Kumbrasev */
16c4568449SPavel Kumbrasev
17c4568449SPavel Kumbrasev #include "threading_control.h"
18c4568449SPavel Kumbrasev #include "permit_manager.h"
19c4568449SPavel Kumbrasev #include "market.h"
20*71e1bb8eSPavel Kumbrasev #include "tcm_adaptor.h"
21c4568449SPavel Kumbrasev #include "thread_dispatcher.h"
22c4568449SPavel Kumbrasev #include "governor.h"
23c4568449SPavel Kumbrasev #include "thread_dispatcher_client.h"
24c4568449SPavel Kumbrasev
25c4568449SPavel Kumbrasev namespace tbb {
26c4568449SPavel Kumbrasev namespace detail {
27c4568449SPavel Kumbrasev namespace r1 {
28c4568449SPavel Kumbrasev
29c4568449SPavel Kumbrasev // ---------------------------------------- threading_control_impl --------------------------------------------------------------
30c4568449SPavel Kumbrasev
31c4568449SPavel Kumbrasev std::size_t global_control_active_value_unsafe(d1::global_control::parameter);
32c4568449SPavel Kumbrasev
calculate_workers_limits()33c4568449SPavel Kumbrasev std::pair<unsigned, unsigned> threading_control_impl::calculate_workers_limits() {
34c4568449SPavel Kumbrasev // Expecting that 4P is suitable for most applications.
35c4568449SPavel Kumbrasev // Limit to 2P for large thread number.
36c4568449SPavel Kumbrasev // TODO: ask RML for max concurrency and possibly correct hard_limit
37c4568449SPavel Kumbrasev unsigned factor = governor::default_num_threads() <= 128 ? 4 : 2;
38c4568449SPavel Kumbrasev
39c4568449SPavel Kumbrasev // The requested number of threads is intentionally not considered in
40c4568449SPavel Kumbrasev // computation of the hard limit, in order to separate responsibilities
41c4568449SPavel Kumbrasev // and avoid complicated interactions between global_control and task_scheduler_init.
42c4568449SPavel Kumbrasev // The threading control guarantees that at least 256 threads might be created.
43c4568449SPavel Kumbrasev unsigned workers_app_limit = global_control_active_value_unsafe(global_control::max_allowed_parallelism);
44c4568449SPavel Kumbrasev unsigned workers_hard_limit = max(max(factor * governor::default_num_threads(), 256u), workers_app_limit);
45c4568449SPavel Kumbrasev unsigned workers_soft_limit = calc_workers_soft_limit(workers_hard_limit);
46c4568449SPavel Kumbrasev
47c4568449SPavel Kumbrasev return std::make_pair(workers_soft_limit, workers_hard_limit);
48c4568449SPavel Kumbrasev }
49c4568449SPavel Kumbrasev
calc_workers_soft_limit(unsigned workers_hard_limit)50c4568449SPavel Kumbrasev unsigned threading_control_impl::calc_workers_soft_limit(unsigned workers_hard_limit) {
51c4568449SPavel Kumbrasev unsigned workers_soft_limit{};
52c4568449SPavel Kumbrasev unsigned soft_limit = global_control_active_value_unsafe(global_control::max_allowed_parallelism);
53c4568449SPavel Kumbrasev
54c4568449SPavel Kumbrasev // if user set no limits (yet), use default value
55c4568449SPavel Kumbrasev workers_soft_limit = soft_limit != 0 ? soft_limit - 1 : governor::default_num_threads() - 1;
56c4568449SPavel Kumbrasev
57c4568449SPavel Kumbrasev if (workers_soft_limit >= workers_hard_limit) {
58c4568449SPavel Kumbrasev workers_soft_limit = workers_hard_limit - 1;
59c4568449SPavel Kumbrasev }
60c4568449SPavel Kumbrasev
61c4568449SPavel Kumbrasev return workers_soft_limit;
62c4568449SPavel Kumbrasev }
63c4568449SPavel Kumbrasev
make_permit_manager(unsigned workers_soft_limit)64c4568449SPavel Kumbrasev cache_aligned_unique_ptr<permit_manager> threading_control_impl::make_permit_manager(unsigned workers_soft_limit) {
65*71e1bb8eSPavel Kumbrasev if (tcm_adaptor::is_initialized()) {
66*71e1bb8eSPavel Kumbrasev auto tcm = make_cache_aligned_unique<tcm_adaptor>();
67*71e1bb8eSPavel Kumbrasev if (tcm->is_connected()) {
68*71e1bb8eSPavel Kumbrasev return tcm;
69*71e1bb8eSPavel Kumbrasev }
70*71e1bb8eSPavel Kumbrasev }
71c4568449SPavel Kumbrasev return make_cache_aligned_unique<market>(workers_soft_limit);
72c4568449SPavel Kumbrasev }
73c4568449SPavel Kumbrasev
make_thread_dispatcher(threading_control & tc,unsigned workers_soft_limit,unsigned workers_hard_limit)74c4568449SPavel Kumbrasev cache_aligned_unique_ptr<thread_dispatcher> threading_control_impl::make_thread_dispatcher(threading_control& tc,
75c4568449SPavel Kumbrasev unsigned workers_soft_limit,
76c4568449SPavel Kumbrasev unsigned workers_hard_limit)
77c4568449SPavel Kumbrasev {
78c4568449SPavel Kumbrasev stack_size_type stack_size = global_control_active_value_unsafe(global_control::thread_stack_size);
79c4568449SPavel Kumbrasev
80c4568449SPavel Kumbrasev cache_aligned_unique_ptr<thread_dispatcher> td =
81c4568449SPavel Kumbrasev make_cache_aligned_unique<thread_dispatcher>(tc, workers_hard_limit, stack_size);
82c4568449SPavel Kumbrasev // This check relies on the fact that for shared RML default_concurrency == max_concurrency
83c4568449SPavel Kumbrasev if (!governor::UsePrivateRML && td->my_server->default_concurrency() < workers_soft_limit) {
84c4568449SPavel Kumbrasev runtime_warning("RML might limit the number of workers to %u while %u is requested.\n",
85c4568449SPavel Kumbrasev td->my_server->default_concurrency(), workers_soft_limit);
86c4568449SPavel Kumbrasev }
87c4568449SPavel Kumbrasev
88c4568449SPavel Kumbrasev return td;
89c4568449SPavel Kumbrasev }
90c4568449SPavel Kumbrasev
threading_control_impl(threading_control * tc)91c4568449SPavel Kumbrasev threading_control_impl::threading_control_impl(threading_control* tc) {
92c4568449SPavel Kumbrasev unsigned workers_soft_limit{}, workers_hard_limit{};
93c4568449SPavel Kumbrasev std::tie(workers_soft_limit, workers_hard_limit) = calculate_workers_limits();
94c4568449SPavel Kumbrasev
95c4568449SPavel Kumbrasev my_permit_manager = make_permit_manager(workers_soft_limit);
96c4568449SPavel Kumbrasev my_thread_dispatcher = make_thread_dispatcher(*tc, workers_soft_limit, workers_hard_limit);
97c4568449SPavel Kumbrasev my_thread_request_serializer =
98c4568449SPavel Kumbrasev make_cache_aligned_unique<thread_request_serializer_proxy>(*my_thread_dispatcher, workers_soft_limit);
99c4568449SPavel Kumbrasev my_permit_manager->set_thread_request_observer(*my_thread_request_serializer);
100c4568449SPavel Kumbrasev
101c4568449SPavel Kumbrasev my_cancellation_disseminator = make_cache_aligned_unique<cancellation_disseminator>();
102c4568449SPavel Kumbrasev my_waiting_threads_monitor = make_cache_aligned_unique<thread_control_monitor>();
103c4568449SPavel Kumbrasev }
104c4568449SPavel Kumbrasev
release(bool blocking_terminate)105c4568449SPavel Kumbrasev void threading_control_impl::release(bool blocking_terminate) {
106c4568449SPavel Kumbrasev my_thread_dispatcher->release(blocking_terminate);
107c4568449SPavel Kumbrasev }
108c4568449SPavel Kumbrasev
set_active_num_workers(unsigned soft_limit)109c4568449SPavel Kumbrasev void threading_control_impl::set_active_num_workers(unsigned soft_limit) {
110c4568449SPavel Kumbrasev __TBB_ASSERT(soft_limit <= my_thread_dispatcher->my_num_workers_hard_limit, nullptr);
111c4568449SPavel Kumbrasev my_thread_request_serializer->set_active_num_workers(soft_limit);
112c4568449SPavel Kumbrasev my_permit_manager->set_active_num_workers(soft_limit);
113c4568449SPavel Kumbrasev }
114c4568449SPavel Kumbrasev
create_client(arena & a)115c4568449SPavel Kumbrasev threading_control_client threading_control_impl::create_client(arena& a) {
116c4568449SPavel Kumbrasev pm_client* pm_client = my_permit_manager->create_client(a);
117c4568449SPavel Kumbrasev thread_dispatcher_client* td_client = my_thread_dispatcher->create_client(a);
118c4568449SPavel Kumbrasev
119c4568449SPavel Kumbrasev return threading_control_client{pm_client, td_client};
120c4568449SPavel Kumbrasev }
121c4568449SPavel Kumbrasev
prepare_client_destruction(threading_control_client client)122c4568449SPavel Kumbrasev threading_control_impl::client_snapshot threading_control_impl::prepare_client_destruction(threading_control_client client) {
123c4568449SPavel Kumbrasev auto td_client = client.get_thread_dispatcher_client();
124c4568449SPavel Kumbrasev return {td_client->get_aba_epoch(), td_client->priority_level(), td_client, client.get_pm_client()};
125c4568449SPavel Kumbrasev }
126c4568449SPavel Kumbrasev
try_destroy_client(threading_control_impl::client_snapshot snapshot)127c4568449SPavel Kumbrasev bool threading_control_impl::try_destroy_client(threading_control_impl::client_snapshot snapshot) {
128c4568449SPavel Kumbrasev if (my_thread_dispatcher->try_unregister_client(snapshot.my_td_client, snapshot.aba_epoch, snapshot.priority_level)) {
129c4568449SPavel Kumbrasev my_permit_manager->unregister_and_destroy_client(*snapshot.my_pm_client);
130c4568449SPavel Kumbrasev return true;
131c4568449SPavel Kumbrasev }
132c4568449SPavel Kumbrasev return false;
133c4568449SPavel Kumbrasev }
134c4568449SPavel Kumbrasev
publish_client(threading_control_client tc_client,d1::constraints & constraints)135*71e1bb8eSPavel Kumbrasev void threading_control_impl::publish_client(threading_control_client tc_client, d1::constraints& constraints) {
136*71e1bb8eSPavel Kumbrasev my_permit_manager->register_client(tc_client.get_pm_client(), constraints);
137c4568449SPavel Kumbrasev my_thread_dispatcher->register_client(tc_client.get_thread_dispatcher_client());
138c4568449SPavel Kumbrasev }
139c4568449SPavel Kumbrasev
register_thread(thread_data & td)140c4568449SPavel Kumbrasev void threading_control_impl::register_thread(thread_data& td) {
141c4568449SPavel Kumbrasev my_cancellation_disseminator->register_thread(td);
142c4568449SPavel Kumbrasev }
unregister_thread(thread_data & td)143c4568449SPavel Kumbrasev void threading_control_impl::unregister_thread(thread_data& td) {
144c4568449SPavel Kumbrasev my_cancellation_disseminator->unregister_thread(td);
145c4568449SPavel Kumbrasev }
146c4568449SPavel Kumbrasev
propagate_task_group_state(std::atomic<uint32_t> d1::task_group_context::* mptr_state,d1::task_group_context & src,uint32_t new_state)147c4568449SPavel Kumbrasev void threading_control_impl::propagate_task_group_state(std::atomic<uint32_t> d1::task_group_context::*mptr_state,
148c4568449SPavel Kumbrasev d1::task_group_context& src, uint32_t new_state)
149c4568449SPavel Kumbrasev {
150c4568449SPavel Kumbrasev my_cancellation_disseminator->propagate_task_group_state(mptr_state, src, new_state);
151c4568449SPavel Kumbrasev }
152c4568449SPavel Kumbrasev
worker_stack_size()153c4568449SPavel Kumbrasev std::size_t threading_control_impl::worker_stack_size() {
154c4568449SPavel Kumbrasev return my_thread_dispatcher->worker_stack_size();
155c4568449SPavel Kumbrasev }
156c4568449SPavel Kumbrasev
max_num_workers()157c4568449SPavel Kumbrasev unsigned threading_control_impl::max_num_workers() {
158c4568449SPavel Kumbrasev return my_thread_dispatcher->my_num_workers_hard_limit;
159c4568449SPavel Kumbrasev }
160c4568449SPavel Kumbrasev
adjust_demand(threading_control_client tc_client,int mandatory_delta,int workers_delta)161c4568449SPavel Kumbrasev void threading_control_impl::adjust_demand(threading_control_client tc_client, int mandatory_delta, int workers_delta) {
162c4568449SPavel Kumbrasev auto& c = *tc_client.get_pm_client();
163c4568449SPavel Kumbrasev my_thread_request_serializer->register_mandatory_request(mandatory_delta);
164c4568449SPavel Kumbrasev my_permit_manager->adjust_demand(c, mandatory_delta, workers_delta);
165c4568449SPavel Kumbrasev }
166c4568449SPavel Kumbrasev
get_waiting_threads_monitor()167c4568449SPavel Kumbrasev thread_control_monitor& threading_control_impl::get_waiting_threads_monitor() {
168c4568449SPavel Kumbrasev return *my_waiting_threads_monitor;
169c4568449SPavel Kumbrasev }
170c4568449SPavel Kumbrasev
171c4568449SPavel Kumbrasev // ---------------------------------------- threading_control -------------------------------------------------------------------
172c4568449SPavel Kumbrasev
173c4568449SPavel Kumbrasev // Defined in global_control.cpp
174c4568449SPavel Kumbrasev void global_control_lock();
175c4568449SPavel Kumbrasev void global_control_unlock();
176c4568449SPavel Kumbrasev
add_ref(bool is_public)177c4568449SPavel Kumbrasev void threading_control::add_ref(bool is_public) {
178c4568449SPavel Kumbrasev ++my_ref_count;
179c4568449SPavel Kumbrasev if (is_public) {
180c4568449SPavel Kumbrasev my_public_ref_count++;
181c4568449SPavel Kumbrasev }
182c4568449SPavel Kumbrasev }
183c4568449SPavel Kumbrasev
remove_ref(bool is_public)184c4568449SPavel Kumbrasev bool threading_control::remove_ref(bool is_public) {
185c4568449SPavel Kumbrasev if (is_public) {
186c4568449SPavel Kumbrasev __TBB_ASSERT(g_threading_control == this, "Global threading control instance was destroyed prematurely?");
187c4568449SPavel Kumbrasev __TBB_ASSERT(my_public_ref_count.load(std::memory_order_relaxed), nullptr);
188c4568449SPavel Kumbrasev --my_public_ref_count;
189c4568449SPavel Kumbrasev }
190c4568449SPavel Kumbrasev
191c4568449SPavel Kumbrasev bool is_last_ref = --my_ref_count == 0;
192c4568449SPavel Kumbrasev if (is_last_ref) {
193c4568449SPavel Kumbrasev __TBB_ASSERT(!my_public_ref_count.load(std::memory_order_relaxed), nullptr);
194c4568449SPavel Kumbrasev g_threading_control = nullptr;
195c4568449SPavel Kumbrasev }
196c4568449SPavel Kumbrasev
197c4568449SPavel Kumbrasev return is_last_ref;
198c4568449SPavel Kumbrasev }
199c4568449SPavel Kumbrasev
get_threading_control(bool is_public)200c4568449SPavel Kumbrasev threading_control* threading_control::get_threading_control(bool is_public) {
201c4568449SPavel Kumbrasev threading_control* control = g_threading_control;
202c4568449SPavel Kumbrasev if (control) {
203c4568449SPavel Kumbrasev control->add_ref(is_public);
204c4568449SPavel Kumbrasev }
205c4568449SPavel Kumbrasev
206c4568449SPavel Kumbrasev return control;
207c4568449SPavel Kumbrasev }
208c4568449SPavel Kumbrasev
create_threading_control()209c4568449SPavel Kumbrasev threading_control* threading_control::create_threading_control() {
210c4568449SPavel Kumbrasev // Global control should be locked before threading_control_impl
211c4568449SPavel Kumbrasev global_control_lock();
212c4568449SPavel Kumbrasev
213c4568449SPavel Kumbrasev threading_control* thr_control{ nullptr };
214c4568449SPavel Kumbrasev try_call([&] {
215c4568449SPavel Kumbrasev global_mutex_type::scoped_lock lock(g_threading_control_mutex);
216c4568449SPavel Kumbrasev
217c4568449SPavel Kumbrasev thr_control = get_threading_control(/*public = */ true);
218c4568449SPavel Kumbrasev if (thr_control == nullptr) {
219c4568449SPavel Kumbrasev thr_control = new (cache_aligned_allocate(sizeof(threading_control))) threading_control(/*public_ref = */ 1, /*private_ref = */ 1);
220c4568449SPavel Kumbrasev thr_control->my_pimpl = make_cache_aligned_unique<threading_control_impl>(thr_control);
221c4568449SPavel Kumbrasev
222c4568449SPavel Kumbrasev __TBB_InitOnce::add_ref();
223c4568449SPavel Kumbrasev
224c4568449SPavel Kumbrasev if (global_control_active_value_unsafe(global_control::scheduler_handle)) {
225c4568449SPavel Kumbrasev ++thr_control->my_public_ref_count;
226c4568449SPavel Kumbrasev ++thr_control->my_ref_count;
227c4568449SPavel Kumbrasev }
228c4568449SPavel Kumbrasev
229c4568449SPavel Kumbrasev g_threading_control = thr_control;
230c4568449SPavel Kumbrasev }
231c4568449SPavel Kumbrasev }).on_exception([&] {
232c4568449SPavel Kumbrasev global_control_unlock();
233c4568449SPavel Kumbrasev
234c4568449SPavel Kumbrasev cache_aligned_deleter deleter{};
235c4568449SPavel Kumbrasev deleter(thr_control);
236c4568449SPavel Kumbrasev });
237c4568449SPavel Kumbrasev
238c4568449SPavel Kumbrasev global_control_unlock();
239c4568449SPavel Kumbrasev return thr_control;
240c4568449SPavel Kumbrasev }
241c4568449SPavel Kumbrasev
destroy()242c4568449SPavel Kumbrasev void threading_control::destroy () {
243c4568449SPavel Kumbrasev cache_aligned_deleter deleter;
244c4568449SPavel Kumbrasev deleter(this);
245c4568449SPavel Kumbrasev __TBB_InitOnce::remove_ref();
246c4568449SPavel Kumbrasev }
247c4568449SPavel Kumbrasev
wait_last_reference(global_mutex_type::scoped_lock & lock)248c4568449SPavel Kumbrasev void threading_control::wait_last_reference(global_mutex_type::scoped_lock& lock) {
249c4568449SPavel Kumbrasev while (my_public_ref_count.load(std::memory_order_relaxed) == 1 && my_ref_count.load(std::memory_order_relaxed) > 1) {
250c4568449SPavel Kumbrasev lock.release();
251c4568449SPavel Kumbrasev // To guarantee that request_close_connection() is called by the last external thread, we need to wait till all
252c4568449SPavel Kumbrasev // references are released. Re-read my_public_ref_count to limit waiting if new external threads are created.
253c4568449SPavel Kumbrasev // Theoretically, new private references to the threading control can be added during waiting making it potentially
254c4568449SPavel Kumbrasev // endless.
255c4568449SPavel Kumbrasev // TODO: revise why the weak scheduler needs threading control's pointer and try to remove this wait.
256c4568449SPavel Kumbrasev // Note that the threading control should know about its schedulers for cancellation/exception/priority propagation,
257c4568449SPavel Kumbrasev // see e.g. task_group_context::cancel_group_execution()
258c4568449SPavel Kumbrasev while (my_public_ref_count.load(std::memory_order_acquire) == 1 && my_ref_count.load(std::memory_order_acquire) > 1) {
259c4568449SPavel Kumbrasev yield();
260c4568449SPavel Kumbrasev }
261c4568449SPavel Kumbrasev lock.acquire(g_threading_control_mutex);
262c4568449SPavel Kumbrasev }
263c4568449SPavel Kumbrasev }
264c4568449SPavel Kumbrasev
release(bool is_public,bool blocking_terminate)265c4568449SPavel Kumbrasev bool threading_control::release(bool is_public, bool blocking_terminate) {
266c4568449SPavel Kumbrasev bool do_release = false;
267c4568449SPavel Kumbrasev {
268c4568449SPavel Kumbrasev global_mutex_type::scoped_lock lock(g_threading_control_mutex);
269c4568449SPavel Kumbrasev if (blocking_terminate) {
270c4568449SPavel Kumbrasev __TBB_ASSERT(is_public, "Only an object with a public reference can request the blocking terminate");
271c4568449SPavel Kumbrasev wait_last_reference(lock);
272c4568449SPavel Kumbrasev }
273c4568449SPavel Kumbrasev do_release = remove_ref(is_public);
274c4568449SPavel Kumbrasev }
275c4568449SPavel Kumbrasev
276c4568449SPavel Kumbrasev if (do_release) {
277c4568449SPavel Kumbrasev __TBB_ASSERT(!my_public_ref_count.load(std::memory_order_relaxed), "No public references must remain if we remove the threading control.");
278c4568449SPavel Kumbrasev // inform RML that blocking termination is required
279c4568449SPavel Kumbrasev my_pimpl->release(blocking_terminate);
280c4568449SPavel Kumbrasev return blocking_terminate;
281c4568449SPavel Kumbrasev }
282c4568449SPavel Kumbrasev return false;
283c4568449SPavel Kumbrasev }
284c4568449SPavel Kumbrasev
threading_control(unsigned public_ref,unsigned ref)285c4568449SPavel Kumbrasev threading_control::threading_control(unsigned public_ref, unsigned ref) : my_public_ref_count(public_ref), my_ref_count(ref)
286c4568449SPavel Kumbrasev {}
287c4568449SPavel Kumbrasev
register_public_reference()288c4568449SPavel Kumbrasev threading_control* threading_control::register_public_reference() {
289c4568449SPavel Kumbrasev threading_control* control{nullptr};
290c4568449SPavel Kumbrasev global_mutex_type::scoped_lock lock(g_threading_control_mutex);
291c4568449SPavel Kumbrasev control = get_threading_control(/*public = */ true);
292c4568449SPavel Kumbrasev if (!control) {
293c4568449SPavel Kumbrasev // We are going to create threading_control_impl, we should acquire mutexes in right order
294c4568449SPavel Kumbrasev lock.release();
295c4568449SPavel Kumbrasev control = create_threading_control();
296c4568449SPavel Kumbrasev }
297c4568449SPavel Kumbrasev
298c4568449SPavel Kumbrasev return control;
299c4568449SPavel Kumbrasev }
300c4568449SPavel Kumbrasev
unregister_public_reference(bool blocking_terminate)301c4568449SPavel Kumbrasev bool threading_control::unregister_public_reference(bool blocking_terminate) {
302c4568449SPavel Kumbrasev __TBB_ASSERT(g_threading_control, "Threading control should exist until last public reference");
303c4568449SPavel Kumbrasev __TBB_ASSERT(g_threading_control->my_public_ref_count.load(std::memory_order_relaxed), nullptr);
304c4568449SPavel Kumbrasev return g_threading_control->release(/*public = */ true, /*blocking_terminate = */ blocking_terminate);
305c4568449SPavel Kumbrasev }
306c4568449SPavel Kumbrasev
create_client(arena & a)307c4568449SPavel Kumbrasev threading_control_client threading_control::create_client(arena& a) {
308c4568449SPavel Kumbrasev {
309c4568449SPavel Kumbrasev global_mutex_type::scoped_lock lock(g_threading_control_mutex);
310c4568449SPavel Kumbrasev add_ref(/*public = */ false);
311c4568449SPavel Kumbrasev }
312c4568449SPavel Kumbrasev
313c4568449SPavel Kumbrasev return my_pimpl->create_client(a);
314c4568449SPavel Kumbrasev }
315c4568449SPavel Kumbrasev
publish_client(threading_control_client client,d1::constraints & constraints)316*71e1bb8eSPavel Kumbrasev void threading_control::publish_client(threading_control_client client, d1::constraints& constraints) {
317*71e1bb8eSPavel Kumbrasev return my_pimpl->publish_client(client, constraints);
318c4568449SPavel Kumbrasev }
319c4568449SPavel Kumbrasev
prepare_client_destruction(threading_control_client client)320c4568449SPavel Kumbrasev threading_control::client_snapshot threading_control::prepare_client_destruction(threading_control_client client) {
321c4568449SPavel Kumbrasev return my_pimpl->prepare_client_destruction(client);
322c4568449SPavel Kumbrasev }
323c4568449SPavel Kumbrasev
try_destroy_client(threading_control::client_snapshot deleter)324c4568449SPavel Kumbrasev bool threading_control::try_destroy_client(threading_control::client_snapshot deleter) {
325c4568449SPavel Kumbrasev bool res = my_pimpl->try_destroy_client(deleter);
326c4568449SPavel Kumbrasev if (res) {
327c4568449SPavel Kumbrasev release(/*public = */ false, /*blocking_terminate = */ false);
328c4568449SPavel Kumbrasev }
329c4568449SPavel Kumbrasev return res;
330c4568449SPavel Kumbrasev }
331c4568449SPavel Kumbrasev
set_active_num_workers(unsigned soft_limit)332c4568449SPavel Kumbrasev void threading_control::set_active_num_workers(unsigned soft_limit) {
333c4568449SPavel Kumbrasev threading_control* thr_control = get_threading_control(/*public = */ false);
334c4568449SPavel Kumbrasev if (thr_control != nullptr) {
335c4568449SPavel Kumbrasev thr_control->my_pimpl->set_active_num_workers(soft_limit);
336c4568449SPavel Kumbrasev thr_control->release(/*is_public=*/false, /*blocking_terminate=*/false);
337c4568449SPavel Kumbrasev }
338c4568449SPavel Kumbrasev }
339c4568449SPavel Kumbrasev
is_present()340c4568449SPavel Kumbrasev bool threading_control::is_present() {
341c4568449SPavel Kumbrasev global_mutex_type::scoped_lock lock(g_threading_control_mutex);
342c4568449SPavel Kumbrasev return g_threading_control != nullptr;
343c4568449SPavel Kumbrasev }
344c4568449SPavel Kumbrasev
register_lifetime_control()345c4568449SPavel Kumbrasev bool threading_control::register_lifetime_control() {
346c4568449SPavel Kumbrasev global_mutex_type::scoped_lock lock(g_threading_control_mutex);
347c4568449SPavel Kumbrasev return get_threading_control(/*public = */ true) != nullptr;
348c4568449SPavel Kumbrasev }
349c4568449SPavel Kumbrasev
unregister_lifetime_control(bool blocking_terminate)350c4568449SPavel Kumbrasev bool threading_control::unregister_lifetime_control(bool blocking_terminate) {
351c4568449SPavel Kumbrasev threading_control* thr_control{nullptr};
352c4568449SPavel Kumbrasev {
353c4568449SPavel Kumbrasev global_mutex_type::scoped_lock lock(g_threading_control_mutex);
354c4568449SPavel Kumbrasev thr_control = g_threading_control;
355c4568449SPavel Kumbrasev }
356c4568449SPavel Kumbrasev
357c4568449SPavel Kumbrasev bool released{true};
358c4568449SPavel Kumbrasev if (thr_control) {
359c4568449SPavel Kumbrasev released = thr_control->release(/*public = */ true, /*blocking_terminate = */ blocking_terminate);
360c4568449SPavel Kumbrasev }
361c4568449SPavel Kumbrasev
362c4568449SPavel Kumbrasev return released;
363c4568449SPavel Kumbrasev }
364c4568449SPavel Kumbrasev
register_thread(thread_data & td)365c4568449SPavel Kumbrasev void threading_control::register_thread(thread_data& td) {
366c4568449SPavel Kumbrasev my_pimpl->register_thread(td);
367c4568449SPavel Kumbrasev }
368c4568449SPavel Kumbrasev
unregister_thread(thread_data & td)369c4568449SPavel Kumbrasev void threading_control::unregister_thread(thread_data& td) {
370c4568449SPavel Kumbrasev my_pimpl->unregister_thread(td);
371c4568449SPavel Kumbrasev }
372c4568449SPavel Kumbrasev
propagate_task_group_state(std::atomic<uint32_t> d1::task_group_context::* mptr_state,d1::task_group_context & src,uint32_t new_state)373c4568449SPavel Kumbrasev void threading_control::propagate_task_group_state(std::atomic<uint32_t> d1::task_group_context::*mptr_state,
374c4568449SPavel Kumbrasev d1::task_group_context& src, uint32_t new_state)
375c4568449SPavel Kumbrasev {
376c4568449SPavel Kumbrasev my_pimpl->propagate_task_group_state(mptr_state, src, new_state);
377c4568449SPavel Kumbrasev }
378c4568449SPavel Kumbrasev
worker_stack_size()379c4568449SPavel Kumbrasev std::size_t threading_control::worker_stack_size() {
380c4568449SPavel Kumbrasev return my_pimpl->worker_stack_size();
381c4568449SPavel Kumbrasev }
382c4568449SPavel Kumbrasev
max_num_workers()383c4568449SPavel Kumbrasev unsigned threading_control::max_num_workers() {
384c4568449SPavel Kumbrasev global_mutex_type::scoped_lock lock(g_threading_control_mutex);
385c4568449SPavel Kumbrasev return g_threading_control ? g_threading_control->my_pimpl->max_num_workers() : 0;
386c4568449SPavel Kumbrasev }
387c4568449SPavel Kumbrasev
adjust_demand(threading_control_client client,int mandatory_delta,int workers_delta)388c4568449SPavel Kumbrasev void threading_control::adjust_demand(threading_control_client client, int mandatory_delta, int workers_delta) {
389c4568449SPavel Kumbrasev my_pimpl->adjust_demand(client, mandatory_delta, workers_delta);
390c4568449SPavel Kumbrasev }
391c4568449SPavel Kumbrasev
get_waiting_threads_monitor()392c4568449SPavel Kumbrasev thread_control_monitor& threading_control::get_waiting_threads_monitor() {
393c4568449SPavel Kumbrasev return my_pimpl->get_waiting_threads_monitor();
394c4568449SPavel Kumbrasev }
395c4568449SPavel Kumbrasev
396c4568449SPavel Kumbrasev } // r1
397c4568449SPavel Kumbrasev } // detail
398c4568449SPavel Kumbrasev } // tbb
399