]> granicus.if.org Git - icinga2/blob - lib/base/asynctask.h
Use BOOST_THROW_EXCEPTION instead of boost::throw_exception()
[icinga2] / lib / base / asynctask.h
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/)        *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #ifndef ASYNCTASK_H
21 #define ASYNCTASK_H 
22
23 namespace icinga
24 {
25
26 /**
27  * An asynchronous task.
28  *
29  * @ingroup base
30  */
31  template<typename TClass, typename TResult>
32 class AsyncTask : public Object
33 {
34 public:
35         typedef shared_ptr<AsyncTask<TClass, TResult> > Ptr;
36         typedef weak_ptr<AsyncTask<TClass, TResult> > WeakPtr;
37
38         /**
39          * A completion callback for an AsyncTask.
40          */
41         typedef function<void (const shared_ptr<TClass>&)> CompletionCallback;
42
43         /**
44          * Constructor for the AsyncTask class.
45          */
46         AsyncTask(void)
47                 : m_Finished(false), m_ResultRetrieved(false)
48         { }
49
50         /**
51          * Destructor for the AsyncTask class.
52          */
53         ~AsyncTask(void)
54         {
55                 if (!m_Finished)
56                         assert(!"Contract violation: AsyncTask was destroyed before its completion callback was invoked.");
57                 else if (!m_ResultRetrieved)
58                         assert(!"Contract violation: AsyncTask was destroyed before its result was retrieved.");
59         }
60
61
62         /**
63          * Starts the async task. The caller must hold a reference to the AsyncTask
64          * object until the completion callback is invoked.
65          */
66         void Start(const CompletionCallback& completionCallback = CompletionCallback())
67         {
68                 m_CompletionCallback = completionCallback;
69
70                 try {
71                         Run();
72                 } catch (...) {
73                         FinishException(boost::current_exception());
74                 }
75         }
76
77         /**
78          * Checks whether the task is finished.
79          */
80         bool IsFinished(void) const
81         {
82                 return m_Finished;
83         }
84
85         /**
86          * Retrieves the result of the task. Throws an exception if one is stored in
87          * the AsyncTask object.
88          *
89          * @returns The task's result.
90          */
91         TResult GetResult(void)
92         {
93                 if (!m_Finished)
94                         BOOST_THROW_EXCEPTION(runtime_error("GetResult called on an unfinished AsyncTask"));
95
96                 if (m_ResultRetrieved)
97                         BOOST_THROW_EXCEPTION(runtime_error("GetResult called on an AsyncTask whose result was already retrieved."));
98
99                 m_ResultRetrieved = true;
100
101                 if (m_Exception)
102                         rethrow_exception(m_Exception);
103
104                 TResult result;
105                 std::swap(m_Result, result);
106                 return result;
107         }
108
109         /**
110          * Finishes the task using an exception.
111          *
112          * @param ex The exception.
113          */
114         void FinishException(const boost::exception_ptr& ex)
115         {
116                 m_Exception = ex;
117                 FinishInternal();
118         }
119
120         /**
121          * Finishes the task using an ordinary result.
122          *
123          * @param result The result.
124          */
125         void FinishResult(const TResult& result)
126         {
127                 m_Result = result;
128                 FinishInternal();
129         }
130
131         /**
132          * Blocks until the task is completed.
133          */
134         void Wait(void)
135         {
136                 Utility::WaitUntil(boost::bind(&AsyncTask<TClass, TResult>::IsFinished, this));
137         }
138
139 protected:
140         /**
141          * Begins executing the task. The Run method must ensure
142          * that one of the Finish*() functions is executed on the task
143          * object (possibly after the Run method has returned).
144          */
145         virtual void Run(void) = 0;
146
147 private:
148         /**
149          * Finishes the task and causes the completion callback to be invoked. This
150          * function must be called before the object is destroyed.
151          */
152         void FinishInternal(void)
153         {
154                 assert(!m_Finished);
155
156                 m_Finished = true;
157
158                 if (!m_CompletionCallback.empty()) {
159                         m_CompletionCallback(GetSelf());
160
161                         /* Clear callback because the bound function might hold a
162                          * reference to this task. */
163                         m_CompletionCallback = CompletionCallback();
164                 }
165         }
166
167         CompletionCallback m_CompletionCallback; /**< The completion callback. */
168         TResult m_Result; /**< The task's result. */
169         boost::exception_ptr m_Exception; /**< The task's exception. */
170
171         bool m_Finished; /**< Whether the task is finished. */
172         bool m_ResultRetrieved; /**< Whether the result was retrieved. */
173 };
174
175 }
176
177 #endif /* ASYNCTASK_H */