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)), m_root(root), m_child(this)
29 {
30 }
31 
33  : m_name(std::move(name)), m_root(parent.m_root), m_child(this)
34 {
35  setParent(parent);
36 }
37 
39 {
40 }
41 
42 void
44 {
45  assert(!hasParent_);
46  assert(!parent.isStopping());
47  assert(std::addressof(m_root) == std::addressof(parent.m_root));
48 
49  parent.m_children.push_front(&m_child);
50  hasParent_ = true;
51 }
52 
53 bool
55 {
56  return m_root.isStopping();
57 }
58 
59 bool
61 {
62  return m_stopped;
63 }
64 
65 bool
67 {
68  return m_childrenStopped;
69 }
70 
71 void
73 {
75  m_is_stopping = true;
76  m_cv.notify_all();
77 }
78 
79 void
81 {
82 }
83 
84 void
86 {
87 }
88 
89 void
91 {
92  stopped();
93 }
94 
95 void
97 {
98 }
99 
100 //------------------------------------------------------------------------------
101 
102 void
104 {
106  iter != m_children.cend();
107  ++iter)
108  iter->stoppable->prepareRecursive();
109  onPrepare();
110 }
111 
112 void
114 {
115  onStart();
117  iter != m_children.cend();
118  ++iter)
119  iter->stoppable->startRecursive();
120 }
121 
122 void
124 {
125  onStop();
126 
128  iter != m_children.cend();
129  ++iter)
130  iter->stoppable->stopAsyncRecursive(j);
131 }
132 
133 void
135 {
136  // Block on each child from the bottom of the tree up.
137  //
139  iter != m_children.cend();
140  ++iter)
141  iter->stoppable->stopRecursive(j);
142 
143  // if we get here then all children have stopped
144  //
145  m_childrenStopped = true;
147 
148  // Now block on this Stoppable until m_is_stopping is set by stopped().
149  //
150  using namespace std::chrono_literals;
152  if (!m_cv.wait_for(lk, 1s, [this] { return m_is_stopping; }))
153  {
154  if (auto stream = j.error())
155  stream << "Waiting for '" << m_name << "' to stop";
156  m_cv.wait(lk, [this] { return m_is_stopping; });
157  }
158  m_stopped = true;
159 }
160 
161 //------------------------------------------------------------------------------
162 
164  : Stoppable(std::move(name), *this)
165 {
166 }
167 
169 {
170  using namespace std::chrono_literals;
172 }
173 
174 bool
176 {
177  return m_calledStop;
178 }
179 
180 void
182 {
183  if (m_prepared.exchange(true) == false)
185 }
186 
187 void
189 {
190  // Courtesy call to prepare.
191  if (m_prepared.exchange(true) == false)
193 
194  if (m_started.exchange(true) == false)
195  startRecursive();
196 }
197 
198 void
200 {
201  // Must have a prior call to start()
202  assert(m_started);
203 
204  if (stopAsync(j))
205  stopRecursive(j);
206 }
207 
208 bool
210 {
211  bool alreadyCalled;
212  {
213  // Even though m_calledStop is atomic, we change its value under a
214  // lock. This removes a small timing window that occurs if the
215  // waiting thread is handling a spurious wakeup while m_calledStop
216  // changes state.
218  alreadyCalled = m_calledStop.exchange(true);
219  }
220  if (alreadyCalled)
221  {
222  if (auto stream = j.warn())
223  stream << "Stoppable::stop called again";
224  return false;
225  }
226 
227  // Wait until all in-flight JobQueue Jobs are completed.
228  using namespace std::chrono_literals;
229  jobCounter_.join(m_name.c_str(), 1s, j);
230 
231  c_.notify_all();
233  return true;
234 }
235 
236 } // namespace ripple
ripple::Stoppable::~Stoppable
virtual ~Stoppable()
Destroy the Stoppable.
Definition: Stoppable.cpp:38
ripple::RootStoppable::~RootStoppable
virtual ~RootStoppable()
Definition: Stoppable.cpp:168
ripple::Stoppable::prepareRecursive
void prepareRecursive()
Definition: Stoppable.cpp:103
ripple::RootStoppable::stopAsync
bool stopAsync(beast::Journal j)
Definition: Stoppable.cpp:209
std::string
STL class.
ripple::RootStoppable::m_prepared
std::atomic< bool > m_prepared
Definition: Stoppable.h:424
ripple::Stoppable::m_stopped
std::atomic< bool > m_stopped
Definition: Stoppable.h:341
ripple::Stoppable::stopped
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
Definition: Stoppable.cpp:72
ripple::Stoppable::onStop
virtual void onStop()
Override called when the stop notification is issued.
Definition: Stoppable.cpp:90
beast::LockFreeStack::cbegin
const_iterator cbegin() const
Definition: LockFreeStack.h:297
ripple::RootStoppable::m_
std::mutex m_
Definition: Stoppable.h:427
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
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:347
ripple::Stoppable::onStart
virtual void onStart()
Override called during start.
Definition: Stoppable.cpp:85
ripple::Stoppable::m_mut
std::mutex m_mut
Definition: Stoppable.h:345
ripple::Stoppable::m_is_stopping
bool m_is_stopping
Definition: Stoppable.h:346
ripple::debugLog
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:452
ripple::Stoppable::setParent
void setParent(Stoppable &parent)
Set the parent of this Stoppable.
Definition: Stoppable.cpp:43
ripple::RootStoppable::prepare
void prepare()
Prepare all contained Stoppable objects.
Definition: Stoppable.cpp:181
beast::LockFreeStackIterator
Definition: LockFreeStack.h:32
ripple::Stoppable::stopAsyncRecursive
void stopAsyncRecursive(beast::Journal j)
Definition: Stoppable.cpp:123
ripple::RootStoppable::stop
void stop(beast::Journal j)
Notify a root stoppable and children to stop, and block until stopped.
Definition: Stoppable.cpp:199
ripple::Stoppable::isStopped
bool isStopped() const
Returns true if the requested stop has completed.
Definition: Stoppable.cpp:60
std::addressof
T addressof(T... args)
ripple::Stoppable::m_children
Children m_children
Definition: Stoppable.h:343
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:200
ripple::RootStoppable
Definition: Stoppable.h:352
ripple::Stoppable::onPrepare
virtual void onPrepare()
Override called during preparation.
Definition: Stoppable.cpp:80
ripple::RootStoppable::isStopping
bool isStopping() const
Definition: Stoppable.cpp:175
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:344
ripple::Stoppable::m_child
Child m_child
Definition: Stoppable.h:340
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::RootStoppable::m_calledStop
std::atomic< bool > m_calledStop
Definition: Stoppable.h:426
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::condition_variable::wait
T wait(T... args)
ripple::Stoppable::stopRecursive
void stopRecursive(beast::Journal j)
Definition: Stoppable.cpp:134
ripple::RootStoppable::m_started
std::atomic< bool > m_started
Definition: Stoppable.h:425
std::condition_variable::wait_for
T wait_for(T... args)
ripple::Stoppable::RootStoppable
friend class RootStoppable
Definition: Stoppable.h:315
ripple::Stoppable::startRecursive
void startRecursive()
Definition: Stoppable.cpp:113
ripple::RootStoppable::start
void start()
Start all contained Stoppable objects.
Definition: Stoppable.cpp:188
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:342
ripple::Stoppable::onChildrenStopped
virtual void onChildrenStopped()
Override called when all children have stopped.
Definition: Stoppable.cpp:96
std
STL namespace.
ripple::Stoppable::m_name
std::string m_name
Definition: Stoppable.h:338
cassert
ripple::RootStoppable::jobCounter_
JobCounter jobCounter_
Definition: Stoppable.h:429
ripple::Stoppable::m_root
RootStoppable & m_root
Definition: Stoppable.h:339
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:152
beast::LockFreeStack::push_front
bool push_front(Node *node)
Push a node onto the stack.
Definition: LockFreeStack.h:222
std::condition_variable::notify_all
T notify_all(T... args)
ripple::RootStoppable::c_
std::condition_variable c_
Definition: Stoppable.h:428
beast::LockFreeStack::cend
const_iterator cend() const
Definition: LockFreeStack.h:303
ripple::Stoppable::isStopping
bool isStopping() const
Returns true if the stoppable should stop.
Definition: Stoppable.cpp:54