CUBRID Engine  latest
thread_looper.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_looper.cpp
21  */
22 
23 #include "thread_looper.hpp"
24 #include "thread_waiter.hpp"
25 
26 #include "perf.hpp"
27 
28 namespace cubthread
29 {
31  // statistics
33 
37  {
39  "looper_sleep_count", "looper_sleep_time"),
40  cubperf::stat_definition (STAT_LOOPER_RESET_COUNT, cubperf::stat_definition::COUNTER, "looper_reset_count")
41  };
42 
44  // looper implementation
46 
48  : m_periods_count (0)
49  , m_periods ()
50  , m_period_index (0)
51  , m_stop (false)
52  , m_was_woken_up (false)
53  , m_setup_period ()
54  , m_start_execution_time ()
55  , m_stats (*Looper_statistics.create_statset ())
56  , m_wait_type (INF_WAITS)
57  {
58  // infinite waits
59  m_setup_period = std::bind (&looper::setup_infinite_wait, std::ref (*this), std::placeholders::_1,
60  std::placeholders::_2);
61  }
62 
63  looper::looper (const looper &other)
64  : looper ()
65  {
68  std::copy (std::begin (other.m_periods), std::end (other.m_periods), std::begin (m_periods));
69 
70  // we need to use same target function, however for default setup function first argument must be this and not
71  // other
72  m_wait_type = other.m_wait_type;
73  switch (other.m_wait_type)
74  {
75  case INF_WAITS:
76  // already bound to looper::setup_infinite_wait
77  break;
78  case FIXED_WAITS:
79  m_setup_period = std::bind (&looper::setup_fixed_waits, std::ref (*this), std::placeholders::_1,
80  std::placeholders::_2);
81  break;
82  case INCREASING_WAITS:
83  m_setup_period = std::bind (&looper::setup_increasing_waits, std::ref (*this), std::placeholders::_1,
84  std::placeholders::_2);
85  break;
86  case CUSTOM_WAITS:
87  m_setup_period = other.m_setup_period; // just copy function
88  break;
89  default:
90  assert (false);
91  break;
92  }
93  }
94 
95  looper::looper (const period_function &setup_period_function)
96  : looper ()
97  {
98  m_setup_period = setup_period_function;
100  }
101 
102  looper::looper (const delta_time &fixed_period)
103  : looper ()
104  {
105  m_periods[0] = fixed_period;
106  m_setup_period = std::bind (&looper::setup_fixed_waits, std::ref (*this), std::placeholders::_1,
107  std::placeholders::_2);
109  }
110 
112  {
113  delete &m_stats;
114  }
115 
116  void
118  {
119  if (is_stopped ())
120  {
121  // stopped; don't put to sleep
122  return;
123  }
124 
126 
128 
129  bool is_timed_wait = true;
130  delta_time period = delta_time (0);
131 
132  m_setup_period (is_timed_wait, period);
133 
134  if (is_timed_wait)
135  {
136  delta_time wait_time = delta_time (0);
137  delta_time execution_time = delta_time (0);
138 
140  {
141  execution_time = std::chrono::system_clock::now () - m_start_execution_time;
142  }
143 
144  // compute task execution time
145  if (period > execution_time)
146  {
147  wait_time = period - execution_time;
148  }
149 
150  m_was_woken_up = waiter_arg.wait_for (wait_time);
151  }
152  else
153  {
154  waiter_arg.wait_inf ();
155  m_was_woken_up = true;
156  }
157 
158  // register start of the task execution time
159  m_start_execution_time = std::chrono::system_clock::now ();
160  Looper_statistics.time_and_increment (m_stats, STAT_LOOPER_SLEEP_COUNT_AND_TIME);
161  }
162 
163  void
165  {
166  m_period_index = 0;
167  Looper_statistics.increment (m_stats, STAT_LOOPER_RESET_COUNT);
168  }
169 
170  bool
172  {
173  return m_stop.exchange (true);
174  }
175 
176  bool
177  looper::is_stopped (void) const
178  {
179  return m_stop;
180  }
181 
182  bool
183  looper::was_woken_up (void) const
184  {
185  return m_was_woken_up;
186  }
187 
188  void
189  looper::setup_fixed_waits (bool &is_timed_wait, delta_time &period)
190  {
191  assert (m_period_index == 0);
192 
193  is_timed_wait = true;
194  period = m_periods[m_period_index];
195  }
196 
197  void
198  looper::setup_infinite_wait (bool &is_timed_wait, delta_time &period)
199  {
200  assert (m_period_index == 0);
201 
202  is_timed_wait = false;
203  }
204 
205  void
206  looper::setup_increasing_waits (bool &is_timed_wait, delta_time &period)
207  {
208  if (m_was_woken_up)
209  {
210  reset ();
211  }
212 
214  {
215  is_timed_wait = true;
216  period = m_periods[m_period_index++];
217  }
218  else
219  {
220  is_timed_wait = false;
221  }
222  }
223 
224  void
226  {
227  Looper_statistics.get_stat_values_with_converted_timers<std::chrono::microseconds> (m_stats, stats_out);
228  }
229 
230  std::size_t
232  {
233  return Looper_statistics.get_value_count ();
234  }
235 
236  const char *
237  looper::get_stat_name (std::size_t stat_index)
238  {
239  return Looper_statistics.get_value_name (stat_index);
240  }
241 
242 } // namespace cubthread
void increment(statset &statsetr, stat_id id, stat_value incr=1) const
Definition: perf.hpp:261
delta_time m_periods[MAX_LOOPER_PERIODS]
static const cubperf::statset_definition Looper_statistics
void put_to_sleep(waiter &waiter_arg)
static void begin(char *test_name)
void time_and_increment(statset &statsetr, stat_id id, duration d, stat_value incr=1) const
Definition: perf.hpp:340
void get_stats(cubperf::stat_value *stats_out)
generic_value< false > stat_value
Definition: perf_def.hpp:46
std::atomic< bool > m_was_woken_up
std::size_t stat_id
Definition: perf_def.hpp:50
std::chrono::system_clock::time_point m_start_execution_time
void get_stat_values_with_converted_timers(const statset &statsetr, stat_value *output_stats) const
Definition: perf.hpp:403
void setup_infinite_wait(bool &is_timed_wait, delta_time &period)
std::size_t get_value_count() const
Definition: perf.cpp:149
#define assert(x)
clock::time_point time_point
Definition: perf_def.hpp:40
std::atomic< bool > m_stop
std::atomic< std::size_t > m_period_index
static cubperf::stat_id STAT_LOOPER_RESET_COUNT
bool was_woken_up(void) const
cubperf::statset & m_stats
static const char * get_stat_name(std::size_t stat_index)
std::chrono::system_clock::duration delta_time
static const cubperf::stat_id STAT_LOOPER_SLEEP_COUNT_AND_TIME
bool is_stopped(void) const
void setup_increasing_waits(bool &is_timed_wait, delta_time &period)
const char * get_value_name(std::size_t value_index) const
Definition: perf.cpp:155
std::function< void(bool &, delta_time &)> period_function
void setup_fixed_waits(bool &is_timed_wait, delta_time &period)
bool wait_for(const std::chrono::system_clock::duration &delta)
period_function m_setup_period
std::size_t m_periods_count
void reset_timept(time_point &timept)
Definition: perf.hpp:623
static std::size_t get_stats_value_count(void)