diff options
author | Dan Vrátil <dvratil@redhat.com> | 2015-02-07 17:51:41 +0100 |
---|---|---|
committer | Dan Vrátil <dvratil@redhat.com> | 2015-02-07 17:51:41 +0100 |
commit | 38afbed3704c5d21db26758d9ce78078710abaa8 (patch) | |
tree | 98864e9bec1cc151042ec7dff46a9897842f92e9 /async/src | |
parent | 7a3ecf3d79ffd8d4c207b42625552da3d57589f5 (diff) | |
download | sink-38afbed3704c5d21db26758d9ce78078710abaa8.tar.gz sink-38afbed3704c5d21db26758d9ce78078710abaa8.zip |
Async: don't leak Executors
We now hold executors in shared pointers. We cannot easilly delete them, as they
are referenced from two objects (the Job they belong to, and the next job), and
the lifetime of the jobs is unclear.
Diffstat (limited to 'async/src')
-rw-r--r-- | async/src/async.cpp | 4 | ||||
-rw-r--r-- | async/src/async.h | 58 |
2 files changed, 30 insertions, 32 deletions
diff --git a/async/src/async.cpp b/async/src/async.cpp index 921a6b5..c9fedc7 100644 --- a/async/src/async.cpp +++ b/async/src/async.cpp | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | using namespace Async; | 25 | using namespace Async; |
26 | 26 | ||
27 | Private::ExecutorBase::ExecutorBase(ExecutorBase* parent) | 27 | Private::ExecutorBase::ExecutorBase(const ExecutorBasePtr &parent) |
28 | : mPrev(parent) | 28 | : mPrev(parent) |
29 | , mResult(0) | 29 | , mResult(0) |
30 | { | 30 | { |
@@ -36,7 +36,7 @@ Private::ExecutorBase::~ExecutorBase() | |||
36 | } | 36 | } |
37 | 37 | ||
38 | 38 | ||
39 | JobBase::JobBase(Private::ExecutorBase *executor) | 39 | JobBase::JobBase(const Private::ExecutorBasePtr &executor) |
40 | : mExecutor(executor) | 40 | : mExecutor(executor) |
41 | { | 41 | { |
42 | } | 42 | } |
diff --git a/async/src/async.h b/async/src/async.h index 753a44f..d15373b 100644 --- a/async/src/async.h +++ b/async/src/async.h | |||
@@ -29,10 +29,12 @@ | |||
29 | 29 | ||
30 | #include <QVector> | 30 | #include <QVector> |
31 | #include <QObject> | 31 | #include <QObject> |
32 | #include <QSharedPointer> | ||
32 | 33 | ||
33 | 34 | ||
34 | /* | 35 | /* |
35 | * TODO: on .then and potentially others: support for ThenTask without future argument and return value which makes it implicitly a sync continuation. Useful for typical value consumer continuations. | 36 | * TODO: on .then and potentially others: support for ThenTask without future argument and return value which makes it implicitly a sync continuation. |
37 | * Useful for typical value consumer continuations. | ||
36 | * TODO: error continuation on .then and others. | 38 | * TODO: error continuation on .then and others. |
37 | * TODO: instead of passing the future objects callbacks could be provided for result reporting (we can still use the future object internally | 39 | * TODO: instead of passing the future objects callbacks could be provided for result reporting (we can still use the future object internally |
38 | */ | 40 | */ |
@@ -57,6 +59,10 @@ using ErrorHandler = std::function<void(int, const QString &)>; | |||
57 | namespace Private | 59 | namespace Private |
58 | { | 60 | { |
59 | 61 | ||
62 | class ExecutorBase; | ||
63 | typedef QSharedPointer<ExecutorBase> ExecutorBasePtr; | ||
64 | |||
65 | |||
60 | template<typename ... T> | 66 | template<typename ... T> |
61 | struct PreviousOut { | 67 | struct PreviousOut { |
62 | using type = typename std::tuple_element<0, std::tuple<T ..., void>>::type; | 68 | using type = typename std::tuple_element<0, std::tuple<T ..., void>>::type; |
@@ -77,9 +83,9 @@ public: | |||
77 | } | 83 | } |
78 | 84 | ||
79 | protected: | 85 | protected: |
80 | ExecutorBase(ExecutorBase *parent); | 86 | ExecutorBase(const ExecutorBasePtr &parent); |
81 | 87 | ||
82 | ExecutorBase *mPrev; | 88 | ExecutorBasePtr mPrev; |
83 | FutureBase *mResult; | 89 | FutureBase *mResult; |
84 | }; | 90 | }; |
85 | 91 | ||
@@ -87,7 +93,7 @@ template<typename PrevOut, typename Out, typename ... In> | |||
87 | class Executor : public ExecutorBase | 93 | class Executor : public ExecutorBase |
88 | { | 94 | { |
89 | protected: | 95 | protected: |
90 | Executor(ExecutorBase *parent) | 96 | Executor(const Private::ExecutorBasePtr &parent) |
91 | : ExecutorBase(parent) | 97 | : ExecutorBase(parent) |
92 | , mPrevFuture(0) | 98 | , mPrevFuture(0) |
93 | {} | 99 | {} |
@@ -106,7 +112,7 @@ template<typename Out, typename ... In> | |||
106 | class ThenExecutor: public Executor<typename PreviousOut<In ...>::type, Out, In ...> | 112 | class ThenExecutor: public Executor<typename PreviousOut<In ...>::type, Out, In ...> |
107 | { | 113 | { |
108 | public: | 114 | public: |
109 | ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler errorHandler = ErrorHandler(), ExecutorBase *parent = nullptr); | 115 | ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler errorHandler = ErrorHandler(), const ExecutorBasePtr &parent = ExecutorBasePtr()); |
110 | void previousFutureReady(); | 116 | void previousFutureReady(); |
111 | }; | 117 | }; |
112 | 118 | ||
@@ -114,7 +120,7 @@ template<typename PrevOut, typename Out, typename In> | |||
114 | class EachExecutor : public Executor<PrevOut, Out, In> | 120 | class EachExecutor : public Executor<PrevOut, Out, In> |
115 | { | 121 | { |
116 | public: | 122 | public: |
117 | EachExecutor(EachTask<Out, In> each, ExecutorBase *parent); | 123 | EachExecutor(EachTask<Out, In> each, const ExecutorBasePtr &parent); |
118 | void previousFutureReady(); | 124 | void previousFutureReady(); |
119 | 125 | ||
120 | private: | 126 | private: |
@@ -122,11 +128,10 @@ private: | |||
122 | }; | 128 | }; |
123 | 129 | ||
124 | template<typename Out, typename In> | 130 | template<typename Out, typename In> |
125 | class ReduceExecutor : public Executor<In, Out, In> | 131 | class ReduceExecutor : public ThenExecutor<Out, In> |
126 | { | 132 | { |
127 | public: | 133 | public: |
128 | ReduceExecutor(ReduceTask<Out, In> reduce, ExecutorBase *parent); | 134 | ReduceExecutor(ReduceTask<Out, In> reduce, const ExecutorBasePtr &parent); |
129 | void previousFutureReady(); | ||
130 | }; | 135 | }; |
131 | 136 | ||
132 | } // namespace Private | 137 | } // namespace Private |
@@ -175,11 +180,11 @@ class JobBase | |||
175 | friend class Job; | 180 | friend class Job; |
176 | 181 | ||
177 | public: | 182 | public: |
178 | JobBase(Private::ExecutorBase *executor); | 183 | JobBase(const Private::ExecutorBasePtr &executor); |
179 | ~JobBase(); | 184 | ~JobBase(); |
180 | 185 | ||
181 | protected: | 186 | protected: |
182 | Private::ExecutorBase *mExecutor; | 187 | Private::ExecutorBasePtr mExecutor; |
183 | }; | 188 | }; |
184 | 189 | ||
185 | /** | 190 | /** |
@@ -237,9 +242,8 @@ public: | |||
237 | template<typename OutOther, typename ... InOther> | 242 | template<typename OutOther, typename ... InOther> |
238 | Job<OutOther, InOther ...> then(ThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc = ErrorHandler()) | 243 | Job<OutOther, InOther ...> then(ThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc = ErrorHandler()) |
239 | { | 244 | { |
240 | //FIXME are we leaking the executor? | 245 | return Job<OutOther, InOther ...>(Private::ExecutorBasePtr( |
241 | //The executor is copied with ever job instance, so use a sharedpointer? | 246 | new Private::ThenExecutor<OutOther, InOther ...>(func, errorFunc, mExecutor))); |
242 | return Job<OutOther, InOther ...>(new Private::ThenExecutor<OutOther, InOther ...>(func, errorFunc, mExecutor)); | ||
243 | } | 247 | } |
244 | 248 | ||
245 | template<typename OutOther, typename InOther> | 249 | template<typename OutOther, typename InOther> |
@@ -249,7 +253,8 @@ public: | |||
249 | "The 'Each' task can only be connected to a job that returns a list or an array."); | 253 | "The 'Each' task can only be connected to a job that returns a list or an array."); |
250 | static_assert(detail::isIterable<OutOther>::value, | 254 | static_assert(detail::isIterable<OutOther>::value, |
251 | "The result type of 'Each' task must be a list or an array."); | 255 | "The result type of 'Each' task must be a list or an array."); |
252 | return Job<OutOther, InOther>(new Private::EachExecutor<Out, OutOther, InOther>(func, mExecutor)); | 256 | return Job<OutOther, InOther>(Private::ExecutorBasePtr( |
257 | new Private::EachExecutor<Out, OutOther, InOther>(func, mExecutor))); | ||
253 | } | 258 | } |
254 | 259 | ||
255 | template<typename OutOther, typename InOther> | 260 | template<typename OutOther, typename InOther> |
@@ -259,7 +264,8 @@ public: | |||
259 | "The 'Result' task can only be connected to a job that returns a list or an array"); | 264 | "The 'Result' task can only be connected to a job that returns a list or an array"); |
260 | static_assert(std::is_same<typename Out::value_type, typename InOther::value_type>::value, | 265 | static_assert(std::is_same<typename Out::value_type, typename InOther::value_type>::value, |
261 | "The return type of previous task must be compatible with input type of this task"); | 266 | "The return type of previous task must be compatible with input type of this task"); |
262 | return Job<OutOther, InOther>(new Private::ReduceExecutor<OutOther, InOther>(func, mExecutor)); | 267 | return Job<OutOther, InOther>(Private::ExecutorBasePtr( |
268 | new Private::ReduceExecutor<OutOther, InOther>(func, mExecutor))); | ||
263 | } | 269 | } |
264 | 270 | ||
265 | Async::Future<Out> exec() | 271 | Async::Future<Out> exec() |
@@ -274,7 +280,7 @@ public: | |||
274 | } | 280 | } |
275 | 281 | ||
276 | private: | 282 | private: |
277 | Job(Private::ExecutorBase *executor) | 283 | Job(Private::ExecutorBasePtr executor) |
278 | : JobBase(executor) | 284 | : JobBase(executor) |
279 | {} | 285 | {} |
280 | }; | 286 | }; |
@@ -289,8 +295,7 @@ namespace Async { | |||
289 | template<typename Out> | 295 | template<typename Out> |
290 | Job<Out> start(ThenTask<Out> func) | 296 | Job<Out> start(ThenTask<Out> func) |
291 | { | 297 | { |
292 | //FIXME we're leaking the exucutor, use a shared pointer | 298 | return Job<Out>(Private::ExecutorBasePtr(new Private::ThenExecutor<Out>(func))); |
293 | return Job<Out>(new Private::ThenExecutor<Out>(func)); | ||
294 | } | 299 | } |
295 | 300 | ||
296 | namespace Private { | 301 | namespace Private { |
@@ -326,7 +331,7 @@ void Executor<PrevOut, Out, In ...>::exec() | |||
326 | } | 331 | } |
327 | 332 | ||
328 | template<typename Out, typename ... In> | 333 | template<typename Out, typename ... In> |
329 | ThenExecutor<Out, In ...>::ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler error, ExecutorBase* parent) | 334 | ThenExecutor<Out, In ...>::ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler error, const ExecutorBasePtr &parent) |
330 | : Executor<typename PreviousOut<In ...>::type, Out, In ...>(parent) | 335 | : Executor<typename PreviousOut<In ...>::type, Out, In ...>(parent) |
331 | { | 336 | { |
332 | this->mFunc = then; | 337 | this->mFunc = then; |
@@ -356,7 +361,7 @@ void ThenExecutor<Out, In ...>::previousFutureReady() | |||
356 | } | 361 | } |
357 | 362 | ||
358 | template<typename PrevOut, typename Out, typename In> | 363 | template<typename PrevOut, typename Out, typename In> |
359 | EachExecutor<PrevOut, Out, In>::EachExecutor(EachTask<Out, In> each, ExecutorBase* parent) | 364 | EachExecutor<PrevOut, Out, In>::EachExecutor(EachTask<Out, In> each, const ExecutorBasePtr &parent) |
360 | : Executor<PrevOut, Out, In>(parent) | 365 | : Executor<PrevOut, Out, In>(parent) |
361 | { | 366 | { |
362 | this->mFunc = each; | 367 | this->mFunc = each; |
@@ -393,18 +398,11 @@ void EachExecutor<PrevOut, Out, In>::previousFutureReady() | |||
393 | } | 398 | } |
394 | 399 | ||
395 | template<typename Out, typename In> | 400 | template<typename Out, typename In> |
396 | ReduceExecutor<Out, In>::ReduceExecutor(ReduceTask<Out, In> reduce, ExecutorBase* parent) | 401 | ReduceExecutor<Out, In>::ReduceExecutor(ReduceTask<Out, In> reduce, const ExecutorBasePtr &parent) |
397 | : Executor<In, Out, In>(parent) | 402 | : ThenExecutor<Out, In>(reduce, ErrorHandler(), parent) |
398 | { | 403 | { |
399 | this->mFunc = reduce; | ||
400 | } | 404 | } |
401 | 405 | ||
402 | template<typename Out, typename In> | ||
403 | void ReduceExecutor<Out, In>::previousFutureReady() | ||
404 | { | ||
405 | assert(this->mPrevFuture->isFinished()); | ||
406 | this->mFunc(this->mPrevFuture->value(), *static_cast<Async::Future<Out>*>(this->mResult)); | ||
407 | } | ||
408 | 406 | ||
409 | } // namespace Private | 407 | } // namespace Private |
410 | 408 | ||