at_fork.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #include "at_fork.h"
  2. #include <library/cpp/yt/memory/leaky_singleton.h>
  3. #include <library/cpp/yt/assert/assert.h>
  4. #ifdef _unix_
  5. #include <pthread.h>
  6. #endif
  7. #include <atomic>
  8. #include <array>
  9. namespace NYT::NThreading {
  10. ////////////////////////////////////////////////////////////////////////////////
  11. class TAtForkManager
  12. {
  13. public:
  14. static TAtForkManager* Get()
  15. {
  16. return LeakySingleton<TAtForkManager>();
  17. }
  18. void RegisterAtForkHandlers(
  19. TAtForkHandler prepare,
  20. TAtForkHandler parent,
  21. TAtForkHandler child)
  22. {
  23. int index = AtForkHandlerCount_++;
  24. Y_ABORT_UNLESS(index < MaxAtForkHandlerSets);
  25. auto& set = AtForkHandlerSets_[index];
  26. set.Prepare = std::move(prepare);
  27. set.Parent = std::move(parent);
  28. set.Child = std::move(child);
  29. set.Initialized.store(true);
  30. }
  31. TReaderWriterSpinLock* GetForkLock()
  32. {
  33. return &ForkLock_;
  34. }
  35. private:
  36. DECLARE_LEAKY_SINGLETON_FRIEND()
  37. TReaderWriterSpinLock ForkLock_;
  38. struct TAtForkHandlerSet
  39. {
  40. TAtForkHandler Prepare;
  41. TAtForkHandler Parent;
  42. TAtForkHandler Child;
  43. std::atomic<bool> Initialized;
  44. };
  45. static constexpr int MaxAtForkHandlerSets = 8;
  46. std::array<TAtForkHandlerSet, MaxAtForkHandlerSets> AtForkHandlerSets_;
  47. std::atomic<int> AtForkHandlerCount_ = 0;
  48. TAtForkManager()
  49. {
  50. #ifdef _unix_
  51. pthread_atfork(
  52. [] { Get()->OnPrepare(); },
  53. [] { Get()->OnParent(); },
  54. [] { Get()->OnChild(); });
  55. #endif
  56. }
  57. void OnPrepare()
  58. {
  59. IterateAtForkHandlerSets([] (const TAtForkHandlerSet& set) {
  60. if (set.Prepare) {
  61. set.Prepare();
  62. }
  63. });
  64. ForkLock_.AcquireWriter();
  65. }
  66. void OnParent()
  67. {
  68. ForkLock_.ReleaseWriter();
  69. IterateAtForkHandlerSets([] (const TAtForkHandlerSet& set) {
  70. if (set.Parent) {
  71. set.Parent();
  72. }
  73. });
  74. }
  75. void OnChild()
  76. {
  77. ForkLock_.ReleaseWriter();
  78. IterateAtForkHandlerSets([] (const TAtForkHandlerSet& set) {
  79. if (set.Child) {
  80. set.Child();
  81. }
  82. });
  83. }
  84. template <class F>
  85. void IterateAtForkHandlerSets(F func)
  86. {
  87. for (const auto& set : AtForkHandlerSets_) {
  88. if (set.Initialized.load()) {
  89. func(set);
  90. }
  91. }
  92. }
  93. };
  94. ////////////////////////////////////////////////////////////////////////////////
  95. static void* AtForkManagerInitializer = [] { return TAtForkManager::Get(); }();
  96. ////////////////////////////////////////////////////////////////////////////////
  97. void RegisterAtForkHandlers(
  98. TAtForkHandler prepare,
  99. TAtForkHandler parent,
  100. TAtForkHandler child)
  101. {
  102. return TAtForkManager::Get()->RegisterAtForkHandlers(
  103. std::move(prepare),
  104. std::move(parent),
  105. std::move(child));
  106. }
  107. TReaderWriterSpinLock* GetForkLock()
  108. {
  109. return TAtForkManager::Get()->GetForkLock();
  110. }
  111. ////////////////////////////////////////////////////////////////////////////////
  112. } // namespace NYT::NThreading