/* * * Copyright 2015 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #ifndef GRPC_CORE_LIB_GPRPP_THD_H #define GRPC_CORE_LIB_GPRPP_THD_H /** Internal thread interface. */ #include #include #include #include #include #include "src/core/lib/gprpp/abstract.h" #include "src/core/lib/gprpp/memory.h" namespace grpc_core { namespace internal { /// Base class for platform-specific thread-state class ThreadInternalsInterface { public: virtual ~ThreadInternalsInterface() {} virtual void Start() GRPC_ABSTRACT; virtual void Join() GRPC_ABSTRACT; GRPC_ABSTRACT_BASE_CLASS }; } // namespace internal class Thread { public: /// Default constructor only to allow use in structs that lack constructors /// Does not produce a validly-constructed thread; must later /// use placement new to construct a real thread. Does not init mu_ and cv_ Thread() : state_(FAKE), impl_(nullptr) {} /// Normal constructor to create a thread with name \a thd_name, /// which will execute a thread based on function \a thd_body /// with argument \a arg once it is started. /// The optional \a success argument indicates whether the thread /// is successfully created. Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg, bool* success = nullptr); /// Move constructor for thread. After this is called, the other thread /// no longer represents a living thread object Thread(Thread&& other) : state_(other.state_), impl_(other.impl_) { other.state_ = MOVED; other.impl_ = nullptr; } /// Move assignment operator for thread. After this is called, the other /// thread no longer represents a living thread object. Not allowed if this /// thread actually exists Thread& operator=(Thread&& other) { if (this != &other) { // TODO(vjpai): if we can be sure that all Thread's are actually // constructed, then we should assert GPR_ASSERT(impl_ == nullptr) here. // However, as long as threads come in structures that are // allocated via gpr_malloc, this will not be the case, so we cannot // assert it for the time being. state_ = other.state_; impl_ = other.impl_; other.state_ = MOVED; other.impl_ = nullptr; } return *this; } /// The destructor is strictly optional; either the thread never came to life /// and the constructor itself killed it or it has already been joined and /// the Join function kills it. The destructor shouldn't have to do anything. ~Thread() { GPR_ASSERT(impl_ == nullptr); } void Start() { if (impl_ != nullptr) { GPR_ASSERT(state_ == ALIVE); state_ = STARTED; impl_->Start(); } else { GPR_ASSERT(state_ == FAILED); } }; void Join() { if (impl_ != nullptr) { impl_->Join(); grpc_core::Delete(impl_); state_ = DONE; impl_ = nullptr; } else { GPR_ASSERT(state_ == FAILED); } }; private: Thread(const Thread&) = delete; Thread& operator=(const Thread&) = delete; /// The thread states are as follows: /// FAKE -- just a dummy placeholder Thread created by the default constructor /// ALIVE -- an actual thread of control exists associated with this thread /// STARTED -- the thread of control has been started /// DONE -- the thread of control has completed and been joined /// FAILED -- the thread of control never came alive /// MOVED -- contents were moved out and we're no longer tracking them enum ThreadState { FAKE, ALIVE, STARTED, DONE, FAILED, MOVED }; ThreadState state_; internal::ThreadInternalsInterface* impl_; }; } // namespace grpc_core #endif /* GRPC_CORE_LIB_GPRPP_THD_H */