| #ifndef THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_UTILS_STD_THREAD_H_ |
| #define THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_UTILS_STD_THREAD_H_ |
| |
| #include <exception> // NOLINT: This is only used/built in gBMC. |
| #include <memory> |
| #include <string> |
| #include <system_error> // NOLINT: This is only used/built in gBMC. |
| #include <thread> // NOLINT: This is only used/built in gBMC. |
| #include <utility> |
| |
| #include "absl/functional/any_invocable.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/time/clock.h" |
| #include "absl/time/time.h" |
| #include "utils/thread.h" |
| |
| inline constexpr int kThreadStartRetryCount = 12; |
| inline constexpr absl::Duration kThreadStartRetrySleepDuration = |
| absl::Seconds(5); |
| |
| namespace milotic { |
| |
| class StdThread : public MiloticThread { |
| public: |
| explicit StdThread(absl::string_view name_prefix, |
| absl::AnyInvocable<void() &&> functor) |
| : name_prefix_(name_prefix), functor_(std::move(functor)) {} |
| |
| absl::Status Start() override { |
| // Wrap the functor in a shared_ptr so we can pass a copy to the thread |
| // lambda. If thread creation fails, the lambda (and its copy of the |
| // shared_ptr) is destroyed, but the underlying functor remains valid for |
| // the next retry. Use std::move(*shared_functor) to properly invoke the |
| // &&-qualified AnyInvocable when the thread actually runs. |
| auto shared_functor = |
| std::make_shared<absl::AnyInvocable<void() &&>>(std::move(functor_)); |
| bool started = false; |
| for (int i = 0; i < kThreadStartRetryCount; ++i) { |
| try { // NOLINT(misc-include-cleaner): This is only used/built in gBMC. |
| thread_ = |
| std::thread([shared_functor]() { std::move (*shared_functor)(); }); |
| started = true; |
| break; |
| } catch (...) { // NOLINT(misc-include-cleaner) |
| LOG(ERROR) << name_prefix_ << " Failed to create/start thread: " |
| << ", retrying in " << kThreadStartRetrySleepDuration; |
| thread_ = std::thread(); |
| absl::SleepFor(kThreadStartRetrySleepDuration); |
| } |
| } |
| |
| if (!started) { |
| return absl::ResourceExhaustedError(absl::StrCat( |
| "Failed to create/start thread after ", |
| kThreadStartRetryCount * kThreadStartRetrySleepDuration)); |
| } |
| return absl::OkStatus(); |
| } |
| void Join() override { thread_.join(); } |
| |
| ~StdThread() override = default; |
| |
| private: |
| std::thread thread_; |
| std::string name_prefix_; |
| absl::AnyInvocable<void() &&> functor_; |
| }; |
| |
| } // namespace milotic |
| |
| #endif // THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_UTILS_STD_THREAD_H_ |