File thread_looper.cpp¶
File List > cubrid > src > thread > thread_looper.cpp
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* 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.
*
*/
/*
* thread_looper.cpp
*/
#include "thread_looper.hpp"
#include "thread_waiter.hpp"
#include "perf.hpp"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
namespace cubthread
{
// statistics
static const cubperf::stat_id STAT_LOOPER_SLEEP_COUNT_AND_TIME = 0;
static cubperf::stat_id STAT_LOOPER_RESET_COUNT = 1;
static const cubperf::statset_definition Looper_statistics =
{
cubperf::stat_definition (STAT_LOOPER_SLEEP_COUNT_AND_TIME, cubperf::stat_definition::COUNTER_AND_TIMER,
"looper_sleep_count", "looper_sleep_time"),
cubperf::stat_definition (STAT_LOOPER_RESET_COUNT, cubperf::stat_definition::COUNTER, "looper_reset_count")
};
// looper implementation
looper::looper ()
: m_periods_count (0)
, m_periods ()
, m_period_index (0)
, m_stop (false)
, m_was_woken_up (false)
, m_setup_period ()
, m_start_execution_time ()
, m_stats (*Looper_statistics.create_statset ())
, m_wait_type (INF_WAITS)
{
// infinite waits
m_setup_period = std::bind (&looper::setup_infinite_wait, std::ref (*this), std::placeholders::_1,
std::placeholders::_2);
}
looper::looper (const looper &other)
: looper ()
{
m_periods_count = other.m_periods_count;
m_start_execution_time = other.m_start_execution_time;
std::copy (std::begin (other.m_periods), std::end (other.m_periods), std::begin (m_periods));
// we need to use same target function, however for default setup function first argument must be this and not
// other
m_wait_type = other.m_wait_type;
switch (other.m_wait_type)
{
case INF_WAITS:
// already bound to looper::setup_infinite_wait
break;
case FIXED_WAITS:
m_setup_period = std::bind (&looper::setup_fixed_waits, std::ref (*this), std::placeholders::_1,
std::placeholders::_2);
break;
case INCREASING_WAITS:
m_setup_period = std::bind (&looper::setup_increasing_waits, std::ref (*this), std::placeholders::_1,
std::placeholders::_2);
break;
case CUSTOM_WAITS:
m_setup_period = other.m_setup_period; // just copy function
break;
default:
assert (false);
break;
}
}
looper::looper (const period_function &setup_period_function)
: looper ()
{
m_setup_period = setup_period_function;
m_wait_type = CUSTOM_WAITS;
}
looper::looper (const delta_time &fixed_period)
: looper ()
{
m_periods[0] = fixed_period;
m_setup_period = std::bind (&looper::setup_fixed_waits, std::ref (*this), std::placeholders::_1,
std::placeholders::_2);
m_wait_type = FIXED_WAITS;
}
looper::~looper (void)
{
delete &m_stats;
}
void
looper::put_to_sleep (waiter &waiter_arg)
{
if (is_stopped ())
{
// stopped; don't put to sleep
return;
}
assert (m_setup_period);
cubperf::reset_timept (m_stats.m_timept);
bool is_timed_wait = true;
delta_time period = delta_time (0);
m_setup_period (is_timed_wait, period);
if (is_timed_wait)
{
delta_time wait_time = delta_time (0);
delta_time execution_time = delta_time (0);
if (m_start_execution_time != std::chrono::system_clock::time_point ())
{
execution_time = std::chrono::system_clock::now () - m_start_execution_time;
}
// compute task execution time
if (period > execution_time)
{
wait_time = period - execution_time;
}
m_was_woken_up = waiter_arg.wait_for (wait_time);
}
else
{
waiter_arg.wait_inf ();
m_was_woken_up = true;
}
// register start of the task execution time
m_start_execution_time = std::chrono::system_clock::now ();
Looper_statistics.time_and_increment (m_stats, STAT_LOOPER_SLEEP_COUNT_AND_TIME);
}
void
looper::reset (void)
{
m_period_index = 0;
Looper_statistics.increment (m_stats, STAT_LOOPER_RESET_COUNT);
}
bool
looper::stop (void)
{
return m_stop.exchange (true);
}
bool
looper::is_stopped (void) const
{
return m_stop;
}
bool
looper::was_woken_up (void) const
{
return m_was_woken_up;
}
void
looper::setup_fixed_waits (bool &is_timed_wait, delta_time &period)
{
assert (m_period_index == 0);
is_timed_wait = true;
period = m_periods[m_period_index];
}
void
looper::setup_infinite_wait (bool &is_timed_wait, delta_time &period)
{
assert (m_period_index == 0);
is_timed_wait = false;
}
void
looper::setup_increasing_waits (bool &is_timed_wait, delta_time &period)
{
if (m_was_woken_up)
{
reset ();
}
if (m_period_index < m_periods_count)
{
is_timed_wait = true;
period = m_periods[m_period_index++];
}
else
{
is_timed_wait = false;
}
}
void
looper::get_stats (cubperf::stat_value *stats_out)
{
Looper_statistics.get_stat_values_with_converted_timers<std::chrono::microseconds> (m_stats, stats_out);
}
std::size_t
looper::get_stats_value_count (void)
{
return Looper_statistics.get_value_count ();
}
const char *
looper::get_stat_name (std::size_t stat_index)
{
return Looper_statistics.get_value_name (stat_index);
}
} // namespace cubthread