• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
~ThreadInternalsInterface()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_
Thread()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
Thread(Thread && other)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.
~Thread()91   ~Thread() { GPR_ASSERT(impl_ == nullptr); }
92 
Start()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 
Join()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