mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Refactor Application shutdown using new Service, AsyncService interfaces
This commit is contained in:
200
src/ripple_basics/utility/Service.cpp
Normal file
200
src/ripple_basics/utility/Service.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 ()
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user