File thread_daemon.cpp¶
File List > cubrid > src > thread > thread_daemon.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_daemon - interface for daemon threads
*/
// own header
#include "thread_daemon.hpp"
// module headers
#include "thread_task.hpp"
// cubrid headers
#include "perf.hpp"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
namespace cubthread
{
// daemon statistics
static const cubperf::stat_id STAT_LOOP_EXECUTE_COUNT_AND_TIME = 0;
static const cubperf::stat_id STAT_LOOP_PAUSE_TIME = 1; // count is same as for execute
static const cubperf::statset_definition Daemon_statistics =
{
cubperf::stat_definition (STAT_LOOP_EXECUTE_COUNT_AND_TIME, cubperf::stat_definition::COUNTER_AND_TIMER,
"daemon_loop_count", "daemon_execute_time"),
cubperf::stat_definition (STAT_LOOP_PAUSE_TIME, cubperf::stat_definition::TIMER,
"daemon_pause_time")
};
// daemon implementation
daemon::daemon (const looper &loop_pattern_arg, entry_manager *entry_manager_arg,
entry_task *exec, const char *name /* = "" */)
: m_waiter ()
, m_looper (loop_pattern_arg)
, m_thread ()
, m_name (name)
, m_stats (daemon::create_statset ())
{
// starts a thread to execute daemon::loop
m_thread = std::thread (daemon::loop_with_context, this, entry_manager_arg, exec, m_name.c_str ());
}
daemon::daemon (const looper &loop_pattern_arg, task_without_context *exec_arg, const char *name)
: m_waiter ()
, m_looper (loop_pattern_arg)
, m_thread ()
, m_name (name)
, m_stats (daemon::create_statset ())
{
m_thread = std::thread (daemon::loop_without_context, this, exec_arg, m_name.c_str ());
}
daemon::~daemon ()
{
// thread must be stopped
stop_execution ();
delete &m_stats;
}
void
daemon::wakeup (void)
{
m_waiter.wakeup ();
}
void
daemon::stop_execution (void)
{
// note: this must not be called concurrently
if (m_looper.stop ())
{
// already stopped
return;
}
// make sure thread will wakeup
wakeup ();
// then wait for thread to finish
m_thread.join ();
}
void daemon::pause (void)
{
m_looper.put_to_sleep (m_waiter);
}
bool
daemon::was_woken_up (void)
{
return m_looper.was_woken_up ();
}
void
daemon::reset_looper (void)
{
m_looper.reset ();
}
void
daemon::get_stats (cubperf::stat_value *stats_out)
{
std::size_t i = 0;
// get daemon stats
Daemon_statistics.get_stat_values_with_converted_timers<std::chrono::microseconds> (m_stats, stats_out);
i += Daemon_statistics.get_value_count ();
// get looper stats
m_looper.get_stats (&stats_out[i]);
i += looper::get_stats_value_count ();
// get waiter stats
m_waiter.get_stats (&stats_out[i]);
// i += waiter::STAT_COUNT;
}
bool
daemon::is_running (void)
{
return m_waiter.is_running ();
}
std::size_t
daemon::get_stats_value_count (void)
{
return Daemon_statistics.get_value_count () + looper::get_stats_value_count() + waiter::get_stats_value_count ();
}
const char *
daemon::get_stat_name (std::size_t stat_index)
{
assert (stat_index < get_stats_value_count ());
// is from daemon?
if (stat_index < Daemon_statistics.get_value_count ())
{
return Daemon_statistics.get_value_name (stat_index);
}
else
{
stat_index -= Daemon_statistics.get_value_count ();
}
// is from looper?
if (stat_index < looper::get_stats_value_count ())
{
return looper::get_stat_name (stat_index);
}
else
{
stat_index -= looper::get_stats_value_count ();
}
// must be from waiter
assert (stat_index < waiter::get_stats_value_count ());
return waiter::get_stat_name (stat_index);
}
cubperf::statset &
daemon::create_statset (void)
{
return *Daemon_statistics.create_statset ();
}
void
daemon::register_stat_start (void)
{
cubperf::reset_timept (m_stats.m_timept);
}
void
daemon::register_stat_pause (void)
{
Daemon_statistics.time (m_stats, STAT_LOOP_PAUSE_TIME);
}
void
daemon::register_stat_execute (void)
{
Daemon_statistics.time_and_increment (m_stats, STAT_LOOP_EXECUTE_COUNT_AND_TIME);
}
void
daemon::loop_with_context (daemon *daemon_arg, entry_manager *entry_manager_arg,
entry_task *exec_arg, const char *name)
{
// its purpose is to help visualize daemon thread stacks
if (!std::string (name).empty ())
{
pthread_setname_np (pthread_self (), std::string (name).substr (0, TASK_COMM_LEN - 1).c_str ());
}
else
{
pthread_setname_np (pthread_self (), "unnamed-daemon");
}
// create execution context
entry &context = entry_manager_arg->create_context ();
daemon_arg->register_stat_start ();
while (!daemon_arg->m_looper.is_stopped ())
{
// execute task
exec_arg->execute (context);
daemon_arg->register_stat_execute ();
// take a break
daemon_arg->pause ();
daemon_arg->register_stat_pause ();
}
entry_manager_arg->stop_execution (context);
// retire execution context
entry_manager_arg->retire_context (context);
// retire task
exec_arg->retire ();
}
void
daemon::loop_without_context (daemon *daemon_arg, task_without_context *exec_arg, const char *name)
{
// its purpose is to help visualize daemon thread stacks
if (!std::string (name).empty ())
{
pthread_setname_np (pthread_self (), std::string (name).substr (0, TASK_COMM_LEN - 1).c_str ());
}
else
{
pthread_setname_np (pthread_self (), "unnamed-daemon");
}
daemon_arg->register_stat_start ();
while (!daemon_arg->m_looper.is_stopped ())
{
// execute task
exec_arg->execute ();
daemon_arg->register_stat_execute ();
// take a break
daemon_arg->pause ();
daemon_arg->register_stat_pause ();
}
// retire task
exec_arg->retire ();
}
} // namespace cubthread