aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/gprpp/thd.h
blob: caf0652c1a70c1d5ef01940fda4be52495640385 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 *
 * 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 <grpc/support/port_platform.h>

#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd_id.h>
#include <grpc/support/time.h>

#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 */