summaryrefslogtreecommitdiffstats
path: root/async/src
diff options
context:
space:
mode:
authorDan Vrátil <dvratil@redhat.com>2015-02-07 17:51:41 +0100
committerDan Vrátil <dvratil@redhat.com>2015-02-07 17:51:41 +0100
commit38afbed3704c5d21db26758d9ce78078710abaa8 (patch)
tree98864e9bec1cc151042ec7dff46a9897842f92e9 /async/src
parent7a3ecf3d79ffd8d4c207b42625552da3d57589f5 (diff)
downloadsink-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.cpp4
-rw-r--r--async/src/async.h58
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
25using namespace Async; 25using namespace Async;
26 26
27Private::ExecutorBase::ExecutorBase(ExecutorBase* parent) 27Private::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
39JobBase::JobBase(Private::ExecutorBase *executor) 39JobBase::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 &)>;
57namespace Private 59namespace Private
58{ 60{
59 61
62class ExecutorBase;
63typedef QSharedPointer<ExecutorBase> ExecutorBasePtr;
64
65
60template<typename ... T> 66template<typename ... T>
61struct PreviousOut { 67struct 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
79protected: 85protected:
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>
87class Executor : public ExecutorBase 93class Executor : public ExecutorBase
88{ 94{
89protected: 95protected:
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>
106class ThenExecutor: public Executor<typename PreviousOut<In ...>::type, Out, In ...> 112class ThenExecutor: public Executor<typename PreviousOut<In ...>::type, Out, In ...>
107{ 113{
108public: 114public:
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>
114class EachExecutor : public Executor<PrevOut, Out, In> 120class EachExecutor : public Executor<PrevOut, Out, In>
115{ 121{
116public: 122public:
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
120private: 126private:
@@ -122,11 +128,10 @@ private:
122}; 128};
123 129
124template<typename Out, typename In> 130template<typename Out, typename In>
125class ReduceExecutor : public Executor<In, Out, In> 131class ReduceExecutor : public ThenExecutor<Out, In>
126{ 132{
127public: 133public:
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
177public: 182public:
178 JobBase(Private::ExecutorBase *executor); 183 JobBase(const Private::ExecutorBasePtr &executor);
179 ~JobBase(); 184 ~JobBase();
180 185
181protected: 186protected:
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
276private: 282private:
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 {
289template<typename Out> 295template<typename Out>
290Job<Out> start(ThenTask<Out> func) 296Job<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
296namespace Private { 301namespace Private {
@@ -326,7 +331,7 @@ void Executor<PrevOut, Out, In ...>::exec()
326} 331}
327 332
328template<typename Out, typename ... In> 333template<typename Out, typename ... In>
329ThenExecutor<Out, In ...>::ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler error, ExecutorBase* parent) 334ThenExecutor<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
358template<typename PrevOut, typename Out, typename In> 363template<typename PrevOut, typename Out, typename In>
359EachExecutor<PrevOut, Out, In>::EachExecutor(EachTask<Out, In> each, ExecutorBase* parent) 364EachExecutor<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
395template<typename Out, typename In> 400template<typename Out, typename In>
396ReduceExecutor<Out, In>::ReduceExecutor(ReduceTask<Out, In> reduce, ExecutorBase* parent) 401ReduceExecutor<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
402template<typename Out, typename In>
403void 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