CUBRID Engine  latest
thread_waiter.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
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 /*
20  * thread_waiter - implementation for suspending/waking threads
21  */
22 
23 #include "thread_waiter.hpp"
24 #include "perf.hpp"
25 
26 #include <cassert>
27 
28 // todo: fix time unit
29 
30 namespace cubthread
31 {
33  // statistics collector
35 
42  {
43  cubperf::stat_definition (STAT_LOCK_WAKEUP_COUNT, cubperf::stat_definition::COUNTER, "waiter_lock_wakeup_count"),
44  cubperf::stat_definition (STAT_SLEEP_COUNT, cubperf::stat_definition::COUNTER, "waiter_sleep_count"),
46  "waiter_timeout_count"),
47  cubperf::stat_definition (STAT_NO_SLEEP_COUNT, cubperf::stat_definition::COUNTER, "waiter_no_sleep_count"),
49  "waiter_awake_count", "waiter_wakeup_delay_time")
50  };
51 
52  // atomic statistics
53  static const char *STAT_WAKEUP_CALL_COUNT_NAME = "waiter_wakeup_count";
54 
56  // waiter
58 
60  : m_mutex ()
61  , m_condvar ()
62  , m_status (RUNNING)
63  , m_stats (*Waiter_statistics.create_statset ())
64  , m_wakeup_calls ("waiter_wakeup_count")
65  , m_was_awaken (false)
66  {
67  }
68 
70  {
71  delete &m_stats;
72  }
73 
74  void
76  {
78 
79  // early out if not sleeping
80  if (m_status != SLEEPING)
81  {
82  /* not sleeping */
83  return;
84  }
85 
86  std::unique_lock<std::mutex> lock (m_mutex);
87  Waiter_statistics.increment (m_stats, STAT_LOCK_WAKEUP_COUNT);
88 
89  if (m_status != SLEEPING)
90  {
91  return;
92  }
93 
94  awake ();
95 
96  // unlock before notifying to avoid blocking the thread on mutex
97  lock.unlock ();
98  m_condvar.notify_one ();
99  }
100 
101  bool
103  {
104  return m_status == AWAKENING;
105  }
106 
107  void
109  {
110  assert (m_status == RUNNING);
111 
112  m_status = SLEEPING;
113 
114  // for statistics
115  m_was_awaken = false;
116  Waiter_statistics.increment (m_stats, STAT_SLEEP_COUNT);
117  }
118 
119  void
121  {
122  assert (m_status == SLEEPING);
123 
125 
126  // for statistics
128  m_was_awaken = true;
129  }
130 
131  void
132  waiter::run (void)
133  {
135 
136  m_status = RUNNING;
137 
138  // for statistics
139  if (m_was_awaken)
140  {
141  Waiter_statistics.time_and_increment (m_stats, STAT_AWAKEN_COUNT_AND_TIME);
142  }
143  }
144 
145  void
147  {
148  std::unique_lock<std::mutex> lock (m_mutex); /* mutex is also locked */
149  goto_sleep ();
150 
151  // wait
152  m_condvar.wait (lock, [this] { return m_status == AWAKENING; });
153 
154  run ();
155 
156  // mutex is automatically unlocked
157  }
158 
159  void
161  {
162  stats_out[0] = m_wakeup_calls.get_count ();
163  Waiter_statistics.get_stat_values_with_converted_timers<std::chrono::microseconds> (m_stats, stats_out + 1);
164  }
165 
166  std::size_t
168  {
169  // total stats count:
170  // one atomic count
171  // + Waiter_statistics
172  return 1 + Waiter_statistics.get_value_count ();
173  }
174 
175  bool
177  {
178  std::unique_lock<std::mutex> lock (m_mutex); /* mutex is also locked */
179 
180  return (m_status == RUNNING);
181  }
182 
183  const char *
184  waiter::get_stat_name (std::size_t stat_index)
185  {
186  assert (stat_index < get_stats_value_count ());
187  if (stat_index == 0)
188  {
189  // atomic wakeup call count statistic is separate
191  }
192  else
193  {
194  return Waiter_statistics.get_value_name (stat_index - 1);
195  }
196  }
197 
198  bool
200  {
201  if (delta == std::chrono::microseconds (0))
202  {
203  Waiter_statistics.increment (m_stats, STAT_NO_SLEEP_COUNT);
204  return true;
205  }
206 
207  bool ret;
208 
209  std::unique_lock<std::mutex> lock (m_mutex); // mutex is also locked
210  goto_sleep ();
211 
212  ret = m_condvar.wait_for (lock, delta, [this] { return m_status == AWAKENING; });
213  if (!ret)
214  {
215  Waiter_statistics.increment (m_stats, STAT_TIMEOUT_COUNT);
216  }
217 
218  run ();
219 
220  // mutex is automatically unlocked
221  return ret;
222  }
223 
224  bool
226  {
227  std::unique_lock<std::mutex> lock (m_mutex); // mutex is also locked
228  goto_sleep ();
229 
230  bool ret = m_condvar.wait_until (lock, timeout_time, [this] { return m_status == AWAKENING; });
231  if (!ret)
232  {
233  Waiter_statistics.increment (m_stats, STAT_TIMEOUT_COUNT);
234  }
235 
236  run ();
237 
238  // mutex is automatically unlocked
239  return ret;
240  }
241 
243  // waiter stats
245 
246 } // namespace cubthread
void increment(statset &statsetr, stat_id id, stat_value incr=1) const
Definition: perf.hpp:261
stat_value get_count(void)
Definition: perf.hpp:499
cubperf::statset & m_stats
void time_and_increment(statset &statsetr, stat_id id, duration d, stat_value incr=1) const
Definition: perf.hpp:340
generic_value< false > stat_value
Definition: perf_def.hpp:46
cubperf::atomic_stat_counter m_wakeup_calls
std::size_t stat_id
Definition: perf_def.hpp:50
static const cubperf::stat_id STAT_AWAKEN_COUNT_AND_TIME
void get_stat_values_with_converted_timers(const statset &statsetr, stat_value *output_stats) const
Definition: perf.hpp:403
std::size_t get_value_count() const
Definition: perf.cpp:149
#define assert(x)
clock::time_point time_point
Definition: perf_def.hpp:40
static const char * STAT_WAKEUP_CALL_COUNT_NAME
static const cubperf::stat_id STAT_LOCK_WAKEUP_COUNT
void get_stats(cubperf::stat_value *stats_out)
static const cubperf::stat_id STAT_NO_SLEEP_COUNT
static const cubperf::stat_id STAT_SLEEP_COUNT
clock::duration duration
Definition: perf_def.hpp:41
const char * get_value_name(std::size_t value_index) const
Definition: perf.cpp:155
static const cubperf::statset_definition Waiter_statistics
static std::size_t get_stats_value_count(void)
bool wait_for(const std::chrono::system_clock::duration &delta)
static const cubperf::stat_id STAT_TIMEOUT_COUNT
void increment(stat_value incr=1)
Definition: perf.hpp:492
static const char * get_stat_name(std::size_t stat_index)
std::condition_variable m_condvar
bool wait_until(const std::chrono::system_clock::time_point &timeout_time)
void reset_timept(time_point &timept)
Definition: perf.hpp:623