Files
xahaud/src/ripple_basics/utility/Service.cpp
2013-09-19 19:41:55 -07:00

201 lines
4.3 KiB
C++

//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
Service::Service (char const* name)
: m_name (name)
, m_root (true)
, m_child (this)
, m_calledServiceStop (false)
, m_stopped (false)
, m_childrenStopped (false)
{
}
Service::Service (char const* name, Service* parent)
: m_name (name)
, m_root (parent != nullptr)
, m_child (this)
, m_calledServiceStop (false)
, m_stopped (false)
, m_childrenStopped (false)
{
if (parent != nullptr)
{
// must not have had stop called
bassert (! parent->isServiceStopping());
parent->m_children.push_front (&m_child);
}
}
Service::Service (char const* name, Service& parent)
: m_name (name)
, m_root (false)
, m_child (this)
, m_calledServiceStop (false)
, m_stopped (false)
, m_childrenStopped (false)
{
// must not have had stop called
bassert (! parent.isServiceStopping());
parent.m_children.push_front (&m_child);
}
Service::~Service ()
{
// must be stopped
bassert (m_stopped);
// children must be stopped
bassert (m_childrenStopped);
}
char const* Service::serviceName () const
{
return m_name;
}
void Service::serviceStop (Journal::Stream stream)
{
// may only be called once
if (m_calledServiceStop)
return;
m_calledServiceStop = true;
// must be called from a root service
bassert (m_root);
// send the notification
serviceStopAsync ();
// now block on the tree of Service objects from the leaves up.
stopRecursive (stream);
}
void Service::serviceStopAsync ()
{
// must be called from a root service
bassert (m_root);
stopAsyncRecursive ();
}
bool Service::isServiceStopping ()
{
return m_calledStopAsync.get() != 0;
}
bool Service::isServiceStopped ()
{
return m_stopped;
}
bool Service::areServiceChildrenStopped ()
{
return m_childrenStopped;
}
void Service::serviceStopped ()
{
m_stoppedEvent.signal();
}
void Service::onServiceStop()
{
serviceStopped();
}
void Service::onServiceChildrenStopped ()
{
}
//------------------------------------------------------------------------------
void Service::stopAsyncRecursive ()
{
// make sure we only do this once
if (m_root)
{
// if this fails, some other thread got to it first
if (! m_calledStopAsync.compareAndSetBool (1, 0))
return;
}
else
{
// can't possibly already be set
bassert (m_calledStopAsync.get() == 0);
m_calledStopAsync.set (1);
}
// notify this service
onServiceStop ();
// notify children
for (Children::const_iterator iter (m_children.cbegin ());
iter != m_children.cend(); ++iter)
{
iter->service->stopAsyncRecursive();
}
}
void Service::stopRecursive (Journal::Stream stream)
{
// Block on each child recursively. Thinking of the Service
// hierarchy as a tree with the root at the top, we will block
// first on leaves, and then at each successivly higher level.
//
for (Children::const_iterator iter (m_children.cbegin ());
iter != m_children.cend(); ++iter)
{
iter->service->stopRecursive (stream);
}
// Once we get here, we either have no children, or all of
// our children have stopped, so update state accordingly.
//
m_childrenStopped = true;
// Notify derived class that children have stopped.
onServiceChildrenStopped ();
// Block until this service stops. First we do a timed wait of 1 second, and
// if that times out we report to the Journal and then do an infinite wait.
//
bool const timedOut (! m_stoppedEvent.wait (1 * 1000)); // milliseconds
if (timedOut)
{
stream << "Service: Waiting for '" << serviceName() << "' to stop";
m_stoppedEvent.wait ();
}
// once we get here, we know the service has stopped.
m_stopped = true;
}
//------------------------------------------------------------------------------
ScopedService::ScopedService (char const* name)
: Service (name)
{
}
ScopedService::~ScopedService ()
{
serviceStop();
}
void ScopedService::onServiceStop ()
{
serviceStopped();
}
void ScopedService::onServiceChildrenStopped ()
{
}