per_thread_sem.cc 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // This file is a no-op if the required LowLevelAlloc support is missing.
  15. #include "y_absl/base/internal/low_level_alloc.h"
  16. #ifndef Y_ABSL_LOW_LEVEL_ALLOC_MISSING
  17. #include "y_absl/synchronization/internal/per_thread_sem.h"
  18. #include <atomic>
  19. #include "y_absl/base/attributes.h"
  20. #include "y_absl/base/internal/thread_identity.h"
  21. #include "y_absl/synchronization/internal/waiter.h"
  22. namespace y_absl {
  23. Y_ABSL_NAMESPACE_BEGIN
  24. namespace synchronization_internal {
  25. void PerThreadSem::SetThreadBlockedCounter(std::atomic<int> *counter) {
  26. base_internal::ThreadIdentity *identity;
  27. identity = GetOrCreateCurrentThreadIdentity();
  28. identity->blocked_count_ptr = counter;
  29. }
  30. std::atomic<int> *PerThreadSem::GetThreadBlockedCounter() {
  31. base_internal::ThreadIdentity *identity;
  32. identity = GetOrCreateCurrentThreadIdentity();
  33. return identity->blocked_count_ptr;
  34. }
  35. void PerThreadSem::Tick(base_internal::ThreadIdentity *identity) {
  36. const int ticker =
  37. identity->ticker.fetch_add(1, std::memory_order_relaxed) + 1;
  38. const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
  39. const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
  40. if (wait_start && (ticker - wait_start > Waiter::kIdlePeriods) && !is_idle) {
  41. // Wakeup the waiting thread since it is time for it to become idle.
  42. Y_ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPoke)(identity);
  43. }
  44. }
  45. } // namespace synchronization_internal
  46. Y_ABSL_NAMESPACE_END
  47. } // namespace y_absl
  48. extern "C" {
  49. Y_ABSL_ATTRIBUTE_WEAK void Y_ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemInit)(
  50. y_absl::base_internal::ThreadIdentity *identity) {
  51. new (y_absl::synchronization_internal::Waiter::GetWaiter(identity))
  52. y_absl::synchronization_internal::Waiter();
  53. }
  54. Y_ABSL_ATTRIBUTE_WEAK void Y_ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(
  55. y_absl::base_internal::ThreadIdentity *identity) {
  56. y_absl::synchronization_internal::Waiter::GetWaiter(identity)->Post();
  57. }
  58. Y_ABSL_ATTRIBUTE_WEAK void Y_ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPoke)(
  59. y_absl::base_internal::ThreadIdentity *identity) {
  60. y_absl::synchronization_internal::Waiter::GetWaiter(identity)->Poke();
  61. }
  62. Y_ABSL_ATTRIBUTE_WEAK bool Y_ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(
  63. y_absl::synchronization_internal::KernelTimeout t) {
  64. bool timeout = false;
  65. y_absl::base_internal::ThreadIdentity *identity;
  66. identity = y_absl::synchronization_internal::GetOrCreateCurrentThreadIdentity();
  67. // Ensure wait_start != 0.
  68. int ticker = identity->ticker.load(std::memory_order_relaxed);
  69. identity->wait_start.store(ticker ? ticker : 1, std::memory_order_relaxed);
  70. identity->is_idle.store(false, std::memory_order_relaxed);
  71. if (identity->blocked_count_ptr != nullptr) {
  72. // Increment count of threads blocked in a given thread pool.
  73. identity->blocked_count_ptr->fetch_add(1, std::memory_order_relaxed);
  74. }
  75. timeout =
  76. !y_absl::synchronization_internal::Waiter::GetWaiter(identity)->Wait(t);
  77. if (identity->blocked_count_ptr != nullptr) {
  78. identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed);
  79. }
  80. identity->is_idle.store(false, std::memory_order_relaxed);
  81. identity->wait_start.store(0, std::memory_order_relaxed);
  82. return !timeout;
  83. }
  84. } // extern "C"
  85. #endif // Y_ABSL_LOW_LEVEL_ALLOC_MISSING