rippled
Stoppable.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/contract.h>
21 #include <ripple/core/Stoppable.h>
22 
23 #include <cassert>
24 
25 namespace ripple {
26 
28  : m_name (std::move (name))
29  , m_root (root)
30  , m_child (this)
31 {
32 }
33 
35  : m_name (std::move (name))
36  , m_root (parent.m_root)
37  , m_child (this)
38 {
39  setParent(parent);
40 }
41 
43 {
44 }
45 
47 {
48  assert(!hasParent_);
49  assert(!parent.isStopping());
50  assert(std::addressof(m_root) == std::addressof(parent.m_root));
51 
52  parent.m_children.push_front(&m_child);
53  hasParent_ = true;
54 }
55 
57 {
58  return m_root.isStopping();
59 }
60 
61 bool Stoppable::isStopped () const
62 {
63  return m_stopped;
64 }
65 
67 {
68  return m_childrenStopped;
69 }
70 
72 {
74  m_is_stopping = true;
75  m_cv.notify_all();
76 }
77 
79 {
80 }
81 
83 {
84 }
85 
87 {
88  stopped();
89 }
90 
92 {
93 }
94 
95 //------------------------------------------------------------------------------
96 
98 {
100  iter != m_children.cend(); ++iter)
101  iter->stoppable->prepareRecursive ();
102  onPrepare ();
103 }
104 
106 {
107  onStart ();
109  iter != m_children.cend(); ++iter)
110  iter->stoppable->startRecursive ();
111 }
112 
114 {
115  onStop ();
116 
118  iter != m_children.cend(); ++iter)
119  iter->stoppable->stopAsyncRecursive(j);
120 }
121 
123 {
124  // Block on each child from the bottom of the tree up.
125  //
127  iter != m_children.cend(); ++iter)
128  iter->stoppable->stopRecursive (j);
129 
130  // if we get here then all children have stopped
131  //
132  m_childrenStopped = true;
134 
135  // Now block on this Stoppable until m_is_stopping is set by stopped().
136  //
137  using namespace std::chrono_literals;
139  if (!m_cv.wait_for(lk, 1s, [this]{return m_is_stopping;}))
140  {
141  if (auto stream = j.error())
142  stream << "Waiting for '" << m_name << "' to stop";
143  m_cv.wait(lk, [this]{return m_is_stopping;});
144  }
145  m_stopped = true;
146 }
147 
148 //------------------------------------------------------------------------------
149 
151  : Stoppable (std::move (name), *this)
152 {
153 }
154 
156 {
157  using namespace std::chrono_literals;
159 }
160 
162 {
163  return m_calledStop;
164 }
165 
167 {
168  if (m_prepared.exchange (true) == false)
169  prepareRecursive ();
170 }
171 
173 {
174  // Courtesy call to prepare.
175  if (m_prepared.exchange (true) == false)
176  prepareRecursive ();
177 
178  if (m_started.exchange (true) == false)
179  startRecursive ();
180 }
181 
183 {
184  // Must have a prior call to start()
185  assert (m_started);
186 
187  if (stopAsync (j))
188  stopRecursive (j);
189 }
190 
192 {
193  bool alreadyCalled;
194  {
195  // Even though m_calledStop is atomic, we change its value under a
196  // lock. This removes a small timing window that occurs if the
197  // waiting thread is handling a spurious wakeup while m_calledStop
198  // changes state.
200  alreadyCalled = m_calledStop.exchange (true);
201  }
202  if (alreadyCalled)
203  {
204  if (auto stream = j.warn())
205  stream << "Stoppable::stop called again";
206  return false;
207  }
208 
209  // Wait until all in-flight JobQueue Jobs are completed.
210  using namespace std::chrono_literals;
211  jobCounter_.join (m_name.c_str(), 1s, j);
212 
213  c_.notify_all();
215  return true;
216 }
217 
218 }
ripple::Stoppable::~Stoppable
virtual ~Stoppable()
Destroy the Stoppable.
Definition: Stoppable.cpp:42
ripple::RootStoppable::~RootStoppable
virtual ~RootStoppable()
Definition: Stoppable.cpp:155
ripple::Stoppable::prepareRecursive
void prepareRecursive()
Definition: Stoppable.cpp:97
ripple::RootStoppable::stopAsync
bool stopAsync(beast::Journal j)
Definition: Stoppable.cpp:191
std::string
STL class.
ripple::RootStoppable::m_prepared
std::atomic< bool > m_prepared
Definition: Stoppable.h:402
ripple::Stoppable::m_stopped
std::atomic< bool > m_stopped
Definition: Stoppable.h:325
ripple::Stoppable::stopped
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
Definition: Stoppable.cpp:71
ripple::Stoppable::onStop
virtual void onStop()
Override called when the stop notification is issued.
Definition: Stoppable.cpp:86
beast::LockFreeStack::cbegin
const_iterator cbegin() const
Definition: LockFreeStack.h:276
ripple::RootStoppable::m_
std::mutex m_
Definition: Stoppable.h:405
beast::Journal::warn
Stream warn() const
Definition: Journal.h:302
std::lock_guard
STL class.
ripple::Stoppable::Stoppable
Stoppable(std::string name, RootStoppable &root)
Definition: Stoppable.cpp:27
ripple::Stoppable::hasParent_
bool hasParent_
Definition: Stoppable.h:331
ripple::Stoppable::onStart
virtual void onStart()
Override called during start.
Definition: Stoppable.cpp:82
ripple::Stoppable::m_mut
std::mutex m_mut
Definition: Stoppable.h:329
ripple::Stoppable::m_is_stopping
bool m_is_stopping
Definition: Stoppable.h:330
ripple::debugLog
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:417
ripple::Stoppable::setParent
void setParent(Stoppable &parent)
Set the parent of this Stoppable.
Definition: Stoppable.cpp:46
ripple::RootStoppable::prepare
void prepare()
Prepare all contained Stoppable objects.
Definition: Stoppable.cpp:166
beast::LockFreeStackIterator
Definition: LockFreeStack.h:32
ripple::Stoppable::stopAsyncRecursive
void stopAsyncRecursive(beast::Journal j)
Definition: Stoppable.cpp:113
ripple::RootStoppable::stop
void stop(beast::Journal j)
Notify a root stoppable and children to stop, and block until stopped.
Definition: Stoppable.cpp:182
ripple::Stoppable::isStopped
bool isStopped() const
Returns true if the requested stop has completed.
Definition: Stoppable.cpp:61
std::addressof
T addressof(T... args)
ripple::Stoppable::m_children
Children m_children
Definition: Stoppable.h:327
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:200
ripple::RootStoppable
Definition: Stoppable.h:336
ripple::Stoppable::onPrepare
virtual void onPrepare()
Override called during preparation.
Definition: Stoppable.cpp:78
ripple::RootStoppable::isStopping
bool isStopping() const
Definition: Stoppable.cpp:161
std::string::c_str
T c_str(T... args)
std::unique_lock
STL class.
ripple::Stoppable::areChildrenStopped
bool areChildrenStopped() const
Returns true if all children have stopped.
Definition: Stoppable.cpp:66
ripple::Stoppable::m_cv
std::condition_variable m_cv
Definition: Stoppable.h:328
ripple::Stoppable::m_child
Child m_child
Definition: Stoppable.h:324
beast::Journal::error
Stream error() const
Definition: Journal.h:307
ripple::RootStoppable::m_calledStop
std::atomic< bool > m_calledStop
Definition: Stoppable.h:404
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
std::condition_variable::wait
T wait(T... args)
ripple::Stoppable::stopRecursive
void stopRecursive(beast::Journal j)
Definition: Stoppable.cpp:122
ripple::RootStoppable::m_started
std::atomic< bool > m_started
Definition: Stoppable.h:403
std::condition_variable::wait_for
T wait_for(T... args)
ripple::Stoppable::RootStoppable
friend class RootStoppable
Definition: Stoppable.h:303
ripple::Stoppable::startRecursive
void startRecursive()
Definition: Stoppable.cpp:105
ripple::RootStoppable::start
void start()
Start all contained Stoppable objects.
Definition: Stoppable.cpp:172
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::atomic::exchange
T exchange(T... args)
ripple::Stoppable::m_childrenStopped
std::atomic< bool > m_childrenStopped
Definition: Stoppable.h:326
ripple::Stoppable::onChildrenStopped
virtual void onChildrenStopped()
Override called when all children have stopped.
Definition: Stoppable.cpp:91
std
STL namespace.
ripple::Stoppable::m_name
std::string m_name
Definition: Stoppable.h:322
cassert
ripple::RootStoppable::jobCounter_
JobCounter jobCounter_
Definition: Stoppable.h:407
ripple::Stoppable::m_root
RootStoppable & m_root
Definition: Stoppable.h:323
ripple::ClosureCounter::join
void join(char const *name, std::chrono::milliseconds wait, beast::Journal j)
Returns once all counted in-flight closures are destroyed.
Definition: ClosureCounter.h:148
beast::LockFreeStack::push_front
bool push_front(Node *node)
Push a node onto the stack.
Definition: LockFreeStack.h:209
std::condition_variable::notify_all
T notify_all(T... args)
ripple::RootStoppable::c_
std::condition_variable c_
Definition: Stoppable.h:406
beast::LockFreeStack::cend
const_iterator cend() const
Definition: LockFreeStack.h:281
ripple::Stoppable::isStopping
bool isStopping() const
Returns true if the stoppable should stop.
Definition: Stoppable.cpp:56