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 stopEntered_;
178 }
179 
180 void
182 {
183  if (startEntered_.exchange(true))
184  return;
186  startRecursive();
187  startExited_ = true;
188 }
189 
190 void
192 {
193  // Must have a prior call to start()
194  assert(startExited_);
195 
196  bool alreadyCalled;
197  {
198  // Even though stopEntered_ is atomic, we change its value under a
199  // lock. This removes a small timing window that occurs if the
200  // waiting thread is handling a spurious wakeup while stopEntered_
201  // changes state.
203  alreadyCalled = stopEntered_.exchange(true);
204  }
205  if (alreadyCalled)
206  {
207  if (auto stream = j.warn())
208  stream << "RootStoppable::stop called again";
209  return;
210  }
211 
212  // Wait until all in-flight JobQueue Jobs are completed.
213  using namespace std::chrono_literals;
214  jobCounter_.join(m_name.c_str(), 1s, j);
215 
216  c_.notify_all();
218  stopRecursive(j);
219 }
220 
221 } // 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
std::string
STL class.
ripple::Stoppable::m_stopped
std::atomic< bool > m_stopped
Definition: Stoppable.h:343
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:411
ripple::RootStoppable::startEntered_
std::atomic< bool > startEntered_
Definition: Stoppable.h:408
ripple::RootStoppable::stopEntered_
std::atomic< bool > stopEntered_
Definition: Stoppable.h:410
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:349
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:347
ripple::Stoppable::m_is_stopping
bool m_is_stopping
Definition: Stoppable.h:348
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
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:191
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:345
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:201
ripple::RootStoppable
Definition: Stoppable.h:354
ripple::RootStoppable::startExited_
std::atomic< bool > startExited_
Definition: Stoppable.h:409
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:346
ripple::Stoppable::m_child
Child m_child
Definition: Stoppable.h:341
beast::Journal::error
Stream error() const
Definition: Journal.h:333
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
std::condition_variable::wait_for
T wait_for(T... args)
ripple::Stoppable::RootStoppable
friend class RootStoppable
Definition: Stoppable.h:316
ripple::Stoppable::startRecursive
void startRecursive()
Definition: Stoppable.cpp:113
ripple::RootStoppable::start
void start()
Prepare and start all contained Stoppable objects.
Definition: Stoppable.cpp:181
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:344
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:339
cassert
ripple::RootStoppable::jobCounter_
JobCounter jobCounter_
Definition: Stoppable.h:413
ripple::Stoppable::m_root
RootStoppable & m_root
Definition: Stoppable.h:340
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:412
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