Panda3D
asyncFuture.I
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file asyncFuture.I
10  * @author rdb
11  * @date 2017-11-28
12  */
13 
14 /**
15  * Initializes the future in the pending state.
16  */
17 INLINE AsyncFuture::
19  _manager(nullptr),
20  _result(nullptr),
21  _future_state(FS_pending) {
22 }
23 
24 /**
25  * Returns true if the future is done or has been cancelled. It is always
26  * safe to call this.
27  */
28 INLINE bool AsyncFuture::
29 done() const {
30  return (FutureState)AtomicAdjust::get(_future_state) >= FS_finished;
31 }
32 
33 /**
34  * Returns true if the future was cancelled. It is always safe to call this.
35  */
36 INLINE bool AsyncFuture::
37 cancelled() const {
38  return (FutureState)AtomicAdjust::get(_future_state) == FS_cancelled;
39 }
40 
41 /**
42  * Sets the event name that will be triggered when the future finishes. Will
43  * not be triggered if the future is cancelled, but it will be triggered for
44  * a coroutine task that exits with an exception.
45  */
46 INLINE void AsyncFuture::
47 set_done_event(const std::string &done_event) {
48  nassertv(!done());
49  _done_event = done_event;
50 }
51 
52 /**
53  * Returns the event name that will be triggered when the future finishes.
54  * See set_done_event().
55  */
56 INLINE const std::string &AsyncFuture::
57 get_done_event() const {
58  return _done_event;
59 }
60 
61 /**
62  * Returns this future's result. Can only be called if done() returns true.
63  */
65 get_result() const {
66  // This is thread safe, since _result may no longer be modified after the
67  // state is changed to "done".
68  nassertr_always(done(), nullptr);
69  return _result;
70 }
71 
72 /**
73  * Returns this future's result as a pair of TypedObject, ReferenceCount
74  * pointers. Can only be called if done() returns true.
75  */
76 INLINE void AsyncFuture::
77 get_result(TypedObject *&ptr, ReferenceCount *&ref_ptr) const {
78  // This is thread safe, since _result may no longer be modified after the
79  // state is changed to "done".
80  nassertd(done()) {
81  ptr = nullptr;
82  ref_ptr = nullptr;
83  }
84  ptr = _result;
85  ref_ptr = _result_ref.p();
86 }
87 
88 /**
89  * Sets this future's result. Can only be called if done() returns false.
90  */
91 INLINE void AsyncFuture::
92 set_result(std::nullptr_t) {
93  set_result(nullptr, nullptr);
94 }
95 
96 INLINE void AsyncFuture::
97 set_result(TypedObject *result) {
98  set_result(result, nullptr);
99 }
100 
101 INLINE void AsyncFuture::
103  set_result(result, result);
104 }
105 
106 INLINE void AsyncFuture::
108  set_result(result, result);
109 }
110 
111 INLINE void AsyncFuture::
112 set_result(const EventParameter &result) {
113  set_result(result.get_ptr(), result.get_ptr());
114 }
115 
116 /**
117  * Creates a new future that returns `done()` when all of the contained
118  * futures are done.
119  *
120  * Calling `cancel()` on the returned future will result in all contained
121  * futures that have not yet finished to be cancelled.
122  */
124 gather(Futures futures) {
125  if (futures.empty()) {
126  AsyncFuture *fut = new AsyncFuture;
127  fut->_future_state = (AtomicAdjust::Integer)FS_finished;
128  return fut;
129  } else if (futures.size() == 1) {
130  return futures[0].p();
131  } else {
132  return (AsyncFuture *)new AsyncGatheringFuture(std::move(futures));
133  }
134 }
135 
136 /**
137  * Tries to atomically lock the future, assuming it is pending. Returns false
138  * if it is not in the pending state, implying it's either done or about to be
139  * cancelled.
140  */
141 INLINE bool AsyncFuture::
142 try_lock_pending() {
143  return set_future_state(FS_locked_pending);
144 }
145 
146 /**
147  * Should be called after try_lock_pending() returns true.
148  */
149 INLINE void AsyncFuture::
150 unlock(FutureState new_state) {
151  nassertv(new_state != FS_locked_pending);
152  FutureState orig_state = (FutureState)AtomicAdjust::set(_future_state, (AtomicAdjust::Integer)new_state);
153  nassertv(orig_state == FS_locked_pending);
154 }
155 
156 /**
157  * Atomically changes the future state from pending to another state. Returns
158  * true if successful, false if the future was already done.
159  * Note that once a future is in a "done" state (ie. cancelled or finished) it
160  * can never change state again.
161  */
162 INLINE bool AsyncFuture::
163 set_future_state(FutureState state) {
164  FutureState orig_state = (FutureState)
166  _future_state,
167  (AtomicAdjust::Integer)FS_pending,
168  (AtomicAdjust::Integer)state);
169 
170  while (orig_state == FS_locked_pending) {
172  orig_state = (FutureState)AtomicAdjust::compare_and_exchange(
173  _future_state,
174  (AtomicAdjust::Integer)FS_pending,
175  (AtomicAdjust::Integer)state);
176  }
177 
178  return orig_state == FS_pending;
179 }
180 
181 /**
182  * Returns the number of futures that were passed to the constructor.
183  */
184 INLINE size_t AsyncGatheringFuture::
186  return _futures.size();
187 }
188 
189 /**
190  * Returns the nth future that was passed into the constructor.
191  */
193 get_future(size_t i) const {
194  nassertr(i < _futures.size(), nullptr);
195  return _futures[i].p();
196 }
197 
198 /**
199  * Returns the result of the nth future that was passed into the constructor.
200  */
202 get_result(size_t i) const {
203  nassertr(i < _futures.size(), nullptr);
204  return _futures[i]->get_result();
205 }
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
Definition: asyncFuture.h:61
An optional parameter associated with an event.
AsyncFuture * get_future(size_t i) const
Returns the nth future that was passed into the constructor.
Definition: asyncFuture.I:193
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
Definition: typedObject.h:88
static void force_yield()
Suspends the current thread for the rest of the current epoch.
Definition: thread.I:201
AsyncFuture()
Initializes the future in the pending state.
Definition: asyncFuture.I:18
TypedObject * get_result() const
Returns this future's result.
Definition: asyncFuture.I:65
set_done_event
Sets the event name that will be triggered when the future finishes.
Definition: asyncFuture.h:77
static AsyncFuture * gather(Futures futures)
Creates a new future that returns `done()` when all of the contained futures are done.
Definition: asyncFuture.I:124
bool done() const
Returns true if the future is done or has been cancelled.
Definition: asyncFuture.I:29
void set_result(std::nullptr_t)
Sets this future's result.
Definition: asyncFuture.I:92
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
Specific future that collects the results of several futures.
Definition: asyncFuture.h:165
TypedWritableReferenceCount * get_ptr() const
Retrieves a pointer to the actual value stored in the parameter.
A base class for all things that want to be reference-counted.
size_t get_num_futures() const
Returns the number of futures that were passed to the constructor.
Definition: asyncFuture.I:185
static Integer set(Integer &var, Integer new_value)
Atomically changes the indicated variable and returns the original value.
bool cancelled() const
Returns true if the future was cancelled.
Definition: asyncFuture.I:37
static Integer compare_and_exchange(Integer &mem, Integer old_value, Integer new_value)
Atomic compare and exchange.