]> git.sesse.net Git - casparcg/blob - tbb30_20100406oss/include/tbb/task_group.h
2.0.2: Updated to boost 1.48.
[casparcg] / tbb30_20100406oss / include / tbb / task_group.h
1 /*
2     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
3
4     This file is part of Threading Building Blocks.
5
6     Threading Building Blocks is free software; you can redistribute it
7     and/or modify it under the terms of the GNU General Public License
8     version 2 as published by the Free Software Foundation.
9
10     Threading Building Blocks is distributed in the hope that it will be
11     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12     of 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 Threading Building Blocks; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     As a special exception, you may use this file as part of a free software
20     library without restriction.  Specifically, if other files instantiate
21     templates or use macros or inline functions from this file, or you compile
22     this file and link it with other files to produce an executable, this
23     file does not by itself cause the resulting executable to be covered by
24     the GNU General Public License.  This exception does not however
25     invalidate any other reasons why the executable file might be covered by
26     the GNU General Public License.
27 */
28
29 #ifndef __TBB_task_group_H
30 #define __TBB_task_group_H
31
32 #include "task.h"
33 #include "tbb_exception.h"
34
35 namespace tbb {
36
37 namespace internal {
38     template<typename F> class task_handle_task;
39 }
40
41 template<typename F>
42 class task_handle : internal::no_assign {
43     template<typename _F> friend class internal::task_handle_task;
44
45     static const intptr_t scheduled = 0x1;
46
47     F my_func;
48     intptr_t my_state;
49
50     void mark_scheduled () {
51         // The check here is intentionally lax to avoid the impact of interlocked operation
52         if ( my_state & scheduled )
53             internal::throw_exception( internal::eid_invalid_multiple_scheduling );
54         my_state |= scheduled;
55     }
56 public:
57     task_handle( const F& f ) : my_func(f), my_state(0) {}
58
59     void operator() () const { my_func(); }
60 };
61
62 enum task_group_status {
63     not_complete,
64     complete,
65     canceled
66 };
67
68 namespace internal {
69
70 // Suppress gratuitous warnings from icc 11.0 when lambda expressions are used in instances of function_task.
71 //#pragma warning(disable: 588)
72
73 template<typename F>
74 class function_task : public task {
75     F my_func;
76     /*override*/ task* execute() {
77         my_func();
78         return NULL;
79     }
80 public:
81     function_task( const F& f ) : my_func(f) {}
82 };
83
84 template<typename F>
85 class task_handle_task : public task {
86     task_handle<F>& my_handle;
87     /*override*/ task* execute() {
88         my_handle();
89         return NULL;
90     }
91 public:
92     task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled(); }
93 };
94
95 class task_group_base : internal::no_copy {
96 protected:
97     empty_task* my_root;
98     task_group_context my_context;
99
100     task& owner () { return *my_root; }
101
102     template<typename F>
103     task_group_status internal_run_and_wait( F& f ) {
104         __TBB_TRY {
105             if ( !my_context.is_group_execution_cancelled() )
106                 f();
107         } __TBB_CATCH( ... ) {
108             my_context.register_pending_exception();
109         }
110         return wait();
111     }
112
113     template<typename F, typename Task>
114     void internal_run( F& f ) {
115         owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) );
116     }
117
118 public:
119     task_group_base( uintptr_t traits = 0 )
120         : my_context(task_group_context::bound, task_group_context::default_traits | traits)
121     {
122         my_root = new( task::allocate_root(my_context) ) empty_task;
123         my_root->set_ref_count(1);
124     }
125
126     template<typename F>
127     void run( task_handle<F>& h ) {
128         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
129     }
130
131     task_group_status wait() {
132         __TBB_TRY {
133             my_root->wait_for_all();
134         } __TBB_CATCH( ... ) {
135             my_context.reset();
136             __TBB_RETHROW();
137         }
138         if ( my_context.is_group_execution_cancelled() ) {
139             my_context.reset();
140             return canceled;
141         }
142         return complete;
143     }
144
145     bool is_canceling() {
146         return my_context.is_group_execution_cancelled();
147     }
148
149     void cancel() {
150         my_context.cancel_group_execution();
151     }
152 }; // class task_group_base
153
154 } // namespace internal
155
156 class task_group : public internal::task_group_base {
157 public:
158     task_group () : task_group_base( task_group_context::concurrent_wait ) {}
159
160     ~task_group() __TBB_TRY {
161         __TBB_ASSERT( my_root->ref_count() != 0, NULL );
162         if( my_root->ref_count() > 1 )
163             my_root->wait_for_all();
164         owner().destroy(*my_root);
165     }
166 #if TBB_USE_EXCEPTIONS
167     catch (...) {
168         owner().destroy(*my_root);
169         throw;
170     }
171 #endif /* TBB_USE_EXCEPTIONS */
172
173 #if __SUNPRO_CC
174     template<typename F>
175     void run( task_handle<F>& h ) {
176         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
177     }
178 #else
179     using task_group_base::run;
180 #endif
181
182     template<typename F>
183     void run( const F& f ) {
184         internal_run< const F, internal::function_task<F> >( f );
185     }
186
187     template<typename F>
188     task_group_status run_and_wait( const F& f ) {
189         return internal_run_and_wait<const F>( f );
190     }
191
192     template<typename F>
193     task_group_status run_and_wait( task_handle<F>& h ) {
194       return internal_run_and_wait< task_handle<F> >( h );
195     }
196 }; // class task_group
197
198 class structured_task_group : public internal::task_group_base {
199 public:
200     ~structured_task_group() {
201         if( my_root->ref_count() > 1 ) {
202             bool stack_unwinding_in_progress = std::uncaught_exception();
203             // Always attempt to do proper cleanup to avoid inevitable memory corruption 
204             // in case of missing wait (for the sake of better testability & debuggability)
205             if ( !is_canceling() )
206                 cancel();
207             my_root->wait_for_all();
208             owner().destroy(*my_root);
209             if ( !stack_unwinding_in_progress )
210                 internal::throw_exception( internal::eid_missing_wait );
211         }
212         else {
213             if( my_root->ref_count() == 1 )
214                 my_root->set_ref_count(0);
215             owner().destroy(*my_root);
216         }
217     }
218
219     template<typename F>
220     task_group_status run_and_wait ( task_handle<F>& h ) {
221         return internal_run_and_wait< task_handle<F> >( h );
222     }
223
224     task_group_status wait() {
225         task_group_status res = task_group_base::wait();
226         my_root->set_ref_count(1);
227         return res;
228     }
229 }; // class structured_task_group
230
231 inline 
232 bool is_current_task_group_canceling() {
233     return task::self().is_cancelled();
234 }
235
236 template<class F>
237 task_handle<F> make_task( const F& f ) {
238     return task_handle<F>( f );
239 }
240
241 } // namespace tbb
242
243 #endif /* __TBB_task_group_H */