1 /* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #ifndef GRPC_CORE_LIB_GPRPP_THD_H 20 #define GRPC_CORE_LIB_GPRPP_THD_H 21 22 /** Internal thread interface. */ 23 24 #include <grpc/support/port_platform.h> 25 26 #include <grpc/support/log.h> 27 #include <grpc/support/sync.h> 28 #include <grpc/support/thd_id.h> 29 #include <grpc/support/time.h> 30 31 #include "src/core/lib/gprpp/abstract.h" 32 #include "src/core/lib/gprpp/memory.h" 33 34 namespace grpc_core { 35 namespace internal { 36 37 /// Base class for platform-specific thread-state 38 class ThreadInternalsInterface { 39 public: 40 virtual ~ThreadInternalsInterface() {} 41 virtual void Start() GRPC_ABSTRACT; 42 virtual void Join() GRPC_ABSTRACT; 43 GRPC_ABSTRACT_BASE_CLASS 44 }; 45 46 } // namespace internal 47 48 class Thread { 49 public: 50 /// Default constructor only to allow use in structs that lack constructors 51 /// Does not produce a validly-constructed thread; must later 52 /// use placement new to construct a real thread. Does not init mu_ and cv_ 53 Thread() : state_(FAKE), impl_(nullptr) {} 54 55 /// Normal constructor to create a thread with name \a thd_name, 56 /// which will execute a thread based on function \a thd_body 57 /// with argument \a arg once it is started. 58 /// The optional \a success argument indicates whether the thread 59 /// is successfully created. 60 Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg, 61 bool* success = nullptr); 62 63 /// Move constructor for thread. After this is called, the other thread 64 /// no longer represents a living thread object 65 Thread(Thread&& other) : state_(other.state_), impl_(other.impl_) { 66 other.state_ = MOVED; 67 other.impl_ = nullptr; 68 } 69 70 /// Move assignment operator for thread. After this is called, the other 71 /// thread no longer represents a living thread object. Not allowed if this 72 /// thread actually exists 73 Thread& operator=(Thread&& other) { 74 if (this != &other) { 75 // TODO(vjpai): if we can be sure that all Thread's are actually 76 // constructed, then we should assert GPR_ASSERT(impl_ == nullptr) here. 77 // However, as long as threads come in structures that are 78 // allocated via gpr_malloc, this will not be the case, so we cannot 79 // assert it for the time being. 80 state_ = other.state_; 81 impl_ = other.impl_; 82 other.state_ = MOVED; 83 other.impl_ = nullptr; 84 } 85 return *this; 86 } 87 88 /// The destructor is strictly optional; either the thread never came to life 89 /// and the constructor itself killed it or it has already been joined and 90 /// the Join function kills it. The destructor shouldn't have to do anything. 91 ~Thread() { GPR_ASSERT(impl_ == nullptr); } 92 93 void Start() { 94 if (impl_ != nullptr) { 95 GPR_ASSERT(state_ == ALIVE); 96 state_ = STARTED; 97 impl_->Start(); 98 } else { 99 GPR_ASSERT(state_ == FAILED); 100 } 101 }; 102 103 void Join() { 104 if (impl_ != nullptr) { 105 impl_->Join(); 106 grpc_core::Delete(impl_); 107 state_ = DONE; 108 impl_ = nullptr; 109 } else { 110 GPR_ASSERT(state_ == FAILED); 111 } 112 }; 113 114 private: 115 Thread(const Thread&) = delete; 116 Thread& operator=(const Thread&) = delete; 117 118 /// The thread states are as follows: 119 /// FAKE -- just a dummy placeholder Thread created by the default constructor 120 /// ALIVE -- an actual thread of control exists associated with this thread 121 /// STARTED -- the thread of control has been started 122 /// DONE -- the thread of control has completed and been joined 123 /// FAILED -- the thread of control never came alive 124 /// MOVED -- contents were moved out and we're no longer tracking them 125 enum ThreadState { FAKE, ALIVE, STARTED, DONE, FAILED, MOVED }; 126 ThreadState state_; 127 internal::ThreadInternalsInterface* impl_; 128 }; 129 130 } // namespace grpc_core 131 132 #endif /* GRPC_CORE_LIB_GPRPP_THD_H */ 133