![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 #ifndef __TBB_task_group_H 00030 #define __TBB_task_group_H 00031 00032 #include "task.h" 00033 #include "tbb_exception.h" 00034 00035 namespace tbb { 00036 00037 namespace internal { 00038 template<typename F> class task_handle_task; 00039 } 00040 00041 template<typename F> 00042 class task_handle : internal::no_assign { 00043 template<typename _F> friend class internal::task_handle_task; 00044 00045 static const intptr_t scheduled = 0x1; 00046 00047 F my_func; 00048 intptr_t my_state; 00049 00050 void mark_scheduled () { 00051 // The check here is intentionally lax to avoid the impact of interlocked operation 00052 if ( my_state & scheduled ) 00053 internal::throw_exception( internal::eid_invalid_multiple_scheduling ); 00054 my_state |= scheduled; 00055 } 00056 public: 00057 task_handle( const F& f ) : my_func(f), my_state(0) {} 00058 00059 void operator() () const { my_func(); } 00060 }; 00061 00062 enum task_group_status { 00063 not_complete, 00064 complete, 00065 canceled 00066 }; 00067 00068 namespace internal { 00069 00070 // Suppress gratuitous warnings from icc 11.0 when lambda expressions are used in instances of function_task. 00071 //#pragma warning(disable: 588) 00072 00073 template<typename F> 00074 class function_task : public task { 00075 F my_func; 00076 /*override*/ task* execute() { 00077 my_func(); 00078 return NULL; 00079 } 00080 public: 00081 function_task( const F& f ) : my_func(f) {} 00082 }; 00083 00084 template<typename F> 00085 class task_handle_task : public task { 00086 task_handle<F>& my_handle; 00087 /*override*/ task* execute() { 00088 my_handle(); 00089 return NULL; 00090 } 00091 public: 00092 task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled(); } 00093 }; 00094 00095 class task_group_base : internal::no_copy { 00096 protected: 00097 empty_task* my_root; 00098 task_group_context my_context; 00099 00100 task& owner () { return *my_root; } 00101 00102 template<typename F> 00103 task_group_status internal_run_and_wait( F& f ) { 00104 __TBB_TRY { 00105 if ( !my_context.is_group_execution_cancelled() ) 00106 f(); 00107 } __TBB_CATCH( ... ) { 00108 my_context.register_pending_exception(); 00109 } 00110 return wait(); 00111 } 00112 00113 template<typename F, typename Task> 00114 void internal_run( F& f ) { 00115 owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) ); 00116 } 00117 00118 public: 00119 task_group_base( uintptr_t traits = 0 ) 00120 : my_context(task_group_context::bound, task_group_context::default_traits | traits) 00121 { 00122 my_root = new( task::allocate_root(my_context) ) empty_task; 00123 my_root->set_ref_count(1); 00124 } 00125 00126 template<typename F> 00127 void run( task_handle<F>& h ) { 00128 internal_run< task_handle<F>, internal::task_handle_task<F> >( h ); 00129 } 00130 00131 task_group_status wait() { 00132 __TBB_TRY { 00133 my_root->wait_for_all(); 00134 } __TBB_CATCH( ... ) { 00135 my_context.reset(); 00136 __TBB_RETHROW(); 00137 } 00138 if ( my_context.is_group_execution_cancelled() ) { 00139 my_context.reset(); 00140 return canceled; 00141 } 00142 return complete; 00143 } 00144 00145 bool is_canceling() { 00146 return my_context.is_group_execution_cancelled(); 00147 } 00148 00149 void cancel() { 00150 my_context.cancel_group_execution(); 00151 } 00152 }; // class task_group_base 00153 00154 } // namespace internal 00155 00156 class task_group : public internal::task_group_base { 00157 public: 00158 task_group () : task_group_base( task_group_context::concurrent_wait ) {} 00159 00160 ~task_group() __TBB_TRY { 00161 __TBB_ASSERT( my_root->ref_count() != 0, NULL ); 00162 if( my_root->ref_count() > 1 ) 00163 my_root->wait_for_all(); 00164 owner().destroy(*my_root); 00165 } 00166 #if TBB_USE_EXCEPTIONS 00167 catch (...) { 00168 owner().destroy(*my_root); 00169 throw; 00170 } 00171 #endif /* TBB_USE_EXCEPTIONS */ 00172 00173 #if __SUNPRO_CC 00174 template<typename F> 00175 void run( task_handle<F>& h ) { 00176 internal_run< task_handle<F>, internal::task_handle_task<F> >( h ); 00177 } 00178 #else 00179 using task_group_base::run; 00180 #endif 00181 00182 template<typename F> 00183 void run( const F& f ) { 00184 internal_run< const F, internal::function_task<F> >( f ); 00185 } 00186 00187 template<typename F> 00188 task_group_status run_and_wait( const F& f ) { 00189 return internal_run_and_wait<const F>( f ); 00190 } 00191 00192 template<typename F> 00193 task_group_status run_and_wait( task_handle<F>& h ) { 00194 return internal_run_and_wait< task_handle<F> >( h ); 00195 } 00196 }; // class task_group 00197 00198 class structured_task_group : public internal::task_group_base { 00199 public: 00200 ~structured_task_group() { 00201 if( my_root->ref_count() > 1 ) { 00202 bool stack_unwinding_in_progress = std::uncaught_exception(); 00203 // Always attempt to do proper cleanup to avoid inevitable memory corruption 00204 // in case of missing wait (for the sake of better testability & debuggability) 00205 if ( !is_canceling() ) 00206 cancel(); 00207 my_root->wait_for_all(); 00208 owner().destroy(*my_root); 00209 if ( !stack_unwinding_in_progress ) 00210 internal::throw_exception( internal::eid_missing_wait ); 00211 } 00212 else { 00213 if( my_root->ref_count() == 1 ) 00214 my_root->set_ref_count(0); 00215 owner().destroy(*my_root); 00216 } 00217 } 00218 00219 template<typename F> 00220 task_group_status run_and_wait ( task_handle<F>& h ) { 00221 return internal_run_and_wait< task_handle<F> >( h ); 00222 } 00223 00224 task_group_status wait() { 00225 task_group_status res = task_group_base::wait(); 00226 my_root->set_ref_count(1); 00227 return res; 00228 } 00229 }; // class structured_task_group 00230 00231 inline 00232 bool is_current_task_group_canceling() { 00233 return task::self().is_cancelled(); 00234 } 00235 00236 template<class F> 00237 task_handle<F> make_task( const F& f ) { 00238 return task_handle<F>( f ); 00239 } 00240 00241 } // namespace tbb 00242 00243 #endif /* __TBB_task_group_H */
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.