Home | History | Annotate | Download | only in gprpp
      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