1349cc55cSDimitry Andric // -*- C++ -*- 2349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 3349cc55cSDimitry Andric // 4349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7349cc55cSDimitry Andric // 8349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 9bdd1243dSDimitry Andric 10349cc55cSDimitry Andric #ifndef _LIBCPP___THREAD_POLL_WITH_BACKOFF_H 11349cc55cSDimitry Andric #define _LIBCPP___THREAD_POLL_WITH_BACKOFF_H 12349cc55cSDimitry Andric 1381ad6265SDimitry Andric #include <__chrono/duration.h> 1481ad6265SDimitry Andric #include <__chrono/high_resolution_clock.h> 15349cc55cSDimitry Andric #include <__config> 16349cc55cSDimitry Andric 17349cc55cSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 18349cc55cSDimitry Andric # pragma GCC system_header 19349cc55cSDimitry Andric #endif 20349cc55cSDimitry Andric 21349cc55cSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 22349cc55cSDimitry Andric 23349cc55cSDimitry Andric static _LIBCPP_CONSTEXPR const int __libcpp_polling_count = 64; 24349cc55cSDimitry Andric 25349cc55cSDimitry Andric // Polls a thread for a condition given by a predicate, and backs off based on a backoff policy 26349cc55cSDimitry Andric // before polling again. 27349cc55cSDimitry Andric // 28*0fca6ea1SDimitry Andric // - __poll is the "test function" that should return true if polling succeeded, and false if it failed. 29349cc55cSDimitry Andric // 30*0fca6ea1SDimitry Andric // - __backoff is the "backoff policy", which is called with the duration since we started polling. It should 31349cc55cSDimitry Andric // return false in order to resume polling, and true if polling should stop entirely for some reason. 32349cc55cSDimitry Andric // In general, backoff policies sleep for some time before returning control to the polling loop. 33349cc55cSDimitry Andric // 34349cc55cSDimitry Andric // - __max_elapsed is the maximum duration to try polling for. If the maximum duration is exceeded, 35349cc55cSDimitry Andric // the polling loop will return false to report a timeout. 36*0fca6ea1SDimitry Andric template <class _Poll, class _Backoff> 37cb14a3feSDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_poll_with_backoff( 38*0fca6ea1SDimitry Andric _Poll&& __poll, _Backoff&& __backoff, chrono::nanoseconds __max_elapsed = chrono::nanoseconds::zero()) { 39349cc55cSDimitry Andric auto const __start = chrono::high_resolution_clock::now(); 40349cc55cSDimitry Andric for (int __count = 0;;) { 41*0fca6ea1SDimitry Andric if (__poll()) 42*0fca6ea1SDimitry Andric return true; // __poll completion means success 43349cc55cSDimitry Andric if (__count < __libcpp_polling_count) { 44349cc55cSDimitry Andric __count += 1; 45349cc55cSDimitry Andric continue; 46349cc55cSDimitry Andric } 47349cc55cSDimitry Andric chrono::nanoseconds const __elapsed = chrono::high_resolution_clock::now() - __start; 48349cc55cSDimitry Andric if (__max_elapsed != chrono::nanoseconds::zero() && __max_elapsed < __elapsed) 49349cc55cSDimitry Andric return false; // timeout failure 50*0fca6ea1SDimitry Andric if (__backoff(__elapsed)) 51*0fca6ea1SDimitry Andric return false; // __backoff completion means failure 52349cc55cSDimitry Andric } 53349cc55cSDimitry Andric } 54349cc55cSDimitry Andric 55349cc55cSDimitry Andric // A trivial backoff policy that always immediately returns the control to 56349cc55cSDimitry Andric // the polling loop. 57349cc55cSDimitry Andric // 58349cc55cSDimitry Andric // This is not very well-behaved since it will cause the polling loop to spin, 59349cc55cSDimitry Andric // so this should most likely only be used on single-threaded systems where there 60349cc55cSDimitry Andric // are no other threads to compete with. 61349cc55cSDimitry Andric struct __spinning_backoff_policy { operator__spinning_backoff_policy62cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(chrono::nanoseconds const&) const { return false; } 63349cc55cSDimitry Andric }; 64349cc55cSDimitry Andric 65349cc55cSDimitry Andric _LIBCPP_END_NAMESPACE_STD 66349cc55cSDimitry Andric 67349cc55cSDimitry Andric #endif // _LIBCPP___THREAD_POLL_WITH_BACKOFF_H 68