1 /* 2 Copyright (c) 2005-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef __TBB_global_control_H 18 #define __TBB_global_control_H 19 20 #include "detail/_config.h" 21 22 #include "detail/_assert.h" 23 #include "detail/_attach.h" 24 #include "detail/_exception.h" 25 #include "detail/_namespace_injection.h" 26 #include "detail/_template_helpers.h" 27 28 #include <cstddef> 29 #include <new> // std::nothrow_t 30 31 namespace tbb { 32 namespace detail { 33 34 namespace d1 { 35 class global_control; 36 class task_scheduler_handle; 37 } 38 39 namespace r1 { 40 TBB_EXPORT void __TBB_EXPORTED_FUNC create(d1::global_control&); 41 TBB_EXPORT void __TBB_EXPORTED_FUNC destroy(d1::global_control&); 42 TBB_EXPORT std::size_t __TBB_EXPORTED_FUNC global_control_active_value(int); 43 struct global_control_impl; 44 struct control_storage_comparator; 45 void release_impl(d1::task_scheduler_handle& handle); 46 bool finalize_impl(d1::task_scheduler_handle& handle); 47 TBB_EXPORT void __TBB_EXPORTED_FUNC get(d1::task_scheduler_handle&); 48 TBB_EXPORT bool __TBB_EXPORTED_FUNC finalize(d1::task_scheduler_handle&, std::intptr_t mode); 49 } 50 51 namespace d1 { 52 53 class global_control { 54 public: 55 enum parameter { 56 max_allowed_parallelism, 57 thread_stack_size, 58 terminate_on_exception, 59 scheduler_handle, // not a public parameter 60 parameter_max // insert new parameters above this point 61 }; 62 63 global_control(parameter p, std::size_t value) : 64 my_value(value), my_reserved(), my_param(p) { 65 suppress_unused_warning(my_reserved); 66 __TBB_ASSERT(my_param < parameter_max, "Invalid parameter"); 67 #if __TBB_WIN8UI_SUPPORT && (_WIN32_WINNT < 0x0A00) 68 // For Windows 8 Store* apps it's impossible to set stack size 69 if (p==thread_stack_size) 70 return; 71 #elif __TBB_x86_64 && (_WIN32 || _WIN64) 72 if (p==thread_stack_size) 73 __TBB_ASSERT_RELEASE((unsigned)value == value, "Stack size is limited to unsigned int range"); 74 #endif 75 if (my_param==max_allowed_parallelism) 76 __TBB_ASSERT_RELEASE(my_value>0, "max_allowed_parallelism cannot be 0."); 77 r1::create(*this); 78 } 79 80 ~global_control() { 81 __TBB_ASSERT(my_param < parameter_max, "Invalid parameter"); 82 #if __TBB_WIN8UI_SUPPORT && (_WIN32_WINNT < 0x0A00) 83 // For Windows 8 Store* apps it's impossible to set stack size 84 if (my_param==thread_stack_size) 85 return; 86 #endif 87 r1::destroy(*this); 88 } 89 90 static std::size_t active_value(parameter p) { 91 __TBB_ASSERT(p < parameter_max, "Invalid parameter"); 92 return r1::global_control_active_value((int)p); 93 } 94 95 private: 96 std::size_t my_value; 97 std::intptr_t my_reserved; // TODO: substitution of global_control* not to break backward compatibility 98 parameter my_param; 99 100 friend struct r1::global_control_impl; 101 friend struct r1::control_storage_comparator; 102 }; 103 104 //! Finalization options. 105 //! Outside of the class to avoid extensive friendship. 106 static constexpr std::intptr_t release_nothrowing = 0; 107 static constexpr std::intptr_t finalize_nothrowing = 1; 108 static constexpr std::intptr_t finalize_throwing = 2; 109 110 //! User side wrapper for a task scheduler lifetime control object 111 class task_scheduler_handle { 112 public: 113 //! Creates an empty task_scheduler_handle 114 task_scheduler_handle() = default; 115 116 //! Creates an attached instance of task_scheduler_handle 117 task_scheduler_handle(attach) { 118 r1::get(*this); 119 } 120 121 //! Release a reference if any 122 ~task_scheduler_handle() { 123 release(); 124 } 125 126 //! No copy 127 task_scheduler_handle(const task_scheduler_handle& other) = delete; 128 task_scheduler_handle& operator=(const task_scheduler_handle& other) = delete; 129 130 //! Move only 131 task_scheduler_handle(task_scheduler_handle&& other) noexcept { 132 std::swap(m_ctl, other.m_ctl); 133 } 134 task_scheduler_handle& operator=(task_scheduler_handle&& other) noexcept { 135 std::swap(m_ctl, other.m_ctl); 136 return *this; 137 }; 138 139 //! Checks if the task_scheduler_handle is empty 140 explicit operator bool() const noexcept { 141 return m_ctl != nullptr; 142 } 143 144 //! Release the reference and deactivate handle 145 void release() { 146 if (m_ctl != nullptr) { 147 r1::finalize(*this, release_nothrowing); 148 m_ctl = nullptr; 149 } 150 } 151 152 private: 153 friend void r1::release_impl(task_scheduler_handle& handle); 154 friend bool r1::finalize_impl(task_scheduler_handle& handle); 155 friend void __TBB_EXPORTED_FUNC r1::get(task_scheduler_handle&); 156 157 friend void finalize(task_scheduler_handle&); 158 friend bool finalize(task_scheduler_handle&, const std::nothrow_t&) noexcept; 159 160 global_control* m_ctl{nullptr}; 161 }; 162 163 #if TBB_USE_EXCEPTIONS 164 //! Waits for worker threads termination. Throws exception on error. 165 inline void finalize(task_scheduler_handle& handle) { 166 try_call([&] { 167 if (handle.m_ctl != nullptr) { 168 bool finalized = r1::finalize(handle, finalize_throwing); 169 __TBB_ASSERT_EX(finalized, "r1::finalize did not respect finalize_throwing ?"); 170 171 } 172 }).on_completion([&] { 173 __TBB_ASSERT(!handle, "The handle should be empty after finalize"); 174 }); 175 } 176 #endif 177 //! Waits for worker threads termination. Returns false on error. 178 inline bool finalize(task_scheduler_handle& handle, const std::nothrow_t&) noexcept { 179 bool finalized = true; 180 if (handle.m_ctl != nullptr) { 181 finalized = r1::finalize(handle, finalize_nothrowing); 182 } 183 __TBB_ASSERT(!handle, "The handle should be empty after finalize"); 184 return finalized; 185 } 186 187 } // namespace d1 188 } // namespace detail 189 190 inline namespace v1 { 191 using detail::d1::global_control; 192 using detail::d1::attach; 193 using detail::d1::finalize; 194 using detail::d1::task_scheduler_handle; 195 using detail::r1::unsafe_wait; 196 } // namespace v1 197 198 } // namespace tbb 199 200 #endif // __TBB_global_control_H 201